home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume26 / port-lpr / part01 next >
Encoding:
Text File  |  1993-04-09  |  136.7 KB  |  4,329 lines

  1. Newsgroups: comp.sources.unix
  2. From: moore@cs.utk.edu (Keith Moore)
  3. Subject: v26i117: port-lpr - portable lpr client for USL and VMS systems, Part01/01
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: moore@cs.utk.edu (Keith Moore)
  8. Posting-Number: Volume 26, Issue 117
  9. Archive-Name: port-lpr/part01
  10.  
  11. This is a standalone lpr client that can be used to submit print jobs over a
  12. network to a machine that runs a Berkeley-style lpd server.  The code is
  13. reasonably portable (not just to UNIX) in that it attempts to compensate for
  14. the differences in the way text files are stored on various systems.
  15.  
  16. It is useful:
  17.  
  18. - on a UNIX machine that doesn't support printing to remote
  19.   Berkeley-style print queues (but which does have TCP), or
  20.  
  21. - to print files to a UNIX print queue from a VAX/VMS machine, either over
  22.   TCP/IP or DECnet.  A gateway from DECnet-based lpr protocol to TCP-based 
  23.   lpr protocol is supplied, but you must have a UNIX box that speaks the 
  24.   DECnet protocol in order to use this.
  25.  
  26. We use it for both purposes at UTK-CS.
  27.  
  28. One of the problems with porting lpr to non-UNIX systems is the fact that
  29. the lpr protocol requires that the client determine the size of a file to be
  30. printed, as it would be stored on UNIX, before sending the file.  This
  31. program accomplishes this by reading the entire file into memory before
  32. transmitting it to the UNIX system.  This allows this lpr client to work on
  33. non-UNIX systems that store files in a different format, but as a result it
  34. cannot print any file that is too big to fit in memory.
  35.  
  36. port-lpr is (nearly) freely redistributable under the terms of the GNU
  37. General Public License.
  38.  
  39. Enjoy.
  40.  
  41.     Keith Moore
  42.     moore@cs.utk.edu
  43.  
  44. #! /bin/sh
  45. # This is a shell archive.  Remove anything before this line, then unpack
  46. # it by saving it into a file and typing "sh file".  To overwrite existing
  47. # files, type "sh file -c".  You can also feed this as standard input via
  48. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  49. # will see the following message at the end:
  50. #        "End of shell archive."
  51. # Contents:  BLURB README MANIFEST LICENSE ChangeLog lpr.c config.h
  52. #   common.h patchlevel.h unix-tcp.c Makefile vms-ucx-tcp.c
  53. #   vms-decnet.c vms-win-tcp.c descrip.mms dnet-lpd-gw.c lpr.man
  54. #   lpr.cat
  55. # Wrapped by moore@thud on Thu May 21 02:16:12 1992
  56. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  57. if test -f 'BLURB' -a "${1}" != "-c" ; then 
  58.   echo shar: Will not clobber existing file \"'BLURB'\"
  59. else
  60. echo shar: Extracting \"'BLURB'\" \(1275 characters\)
  61. sed "s/^X//" >'BLURB' <<'END_OF_FILE'
  62. This is a standalone lpr client that can be used to submit print jobs
  63. over a network to a machine that runs a Berkeley-style lpd server.
  64. The code is reasonably portable (not just to UNIX) and attempts to
  65. compensate for the differences in the way text files are stored on
  66. various systems.
  67. X
  68. It might be useful, for instance:
  69. X
  70. X- on a UNIX machine that doesn't support printing to remote
  71. X  Berkeley-style print queues, or
  72. X
  73. X- to print files to a UNIX print queue from a VAX/VMS machine, either over
  74. X  TCP/IP or DECnet.  A gateway from DECnet-based lpr protocol to TCP-based 
  75. X  lpr protocol is supplied, but you must have a UNIX box that speaks the 
  76. X  DECnet protocol in order to use this.
  77. X
  78. One of the major problems with porting lpr to other systems is the
  79. fact that the lpr protocol requires that the client determine the size
  80. of a file to be printed, as it would be stored on UNIX, before sending
  81. the file.  This program accomplishes this by reading the entire file
  82. into memory before transmitting it to the UNIX system.  This allows
  83. this lpr client to work on non-UNIX systems that store files in a
  84. different format, but it cannot print any file that is too big to fit
  85. in memory.
  86. X
  87. port-lpr is (almost) freely redistributable under the terms of the GNU
  88. General Public License.
  89. X
  90. END_OF_FILE
  91. if test 1275 -ne `wc -c <'BLURB'`; then
  92.     echo shar: \"'BLURB'\" unpacked with wrong size!
  93. fi
  94. # end of 'BLURB'
  95. fi
  96. if test -f 'README' -a "${1}" != "-c" ; then 
  97.   echo shar: Will not clobber existing file \"'README'\"
  98. else
  99. echo shar: Extracting \"'README'\" \(9221 characters\)
  100. sed "s/^X//" >'README' <<'END_OF_FILE'
  101. This is something I threw together to allow various non-BSD systems to
  102. print over the network to print queues on BSD-style systems (like
  103. SunOS and Ultrix and...).  Basically, it's a standalone clone of the
  104. BSD "lpr" command -- like BSD lpr but it doesn't need a print spooler
  105. on the local machine.  This program also runs on VMS systems, and
  106. there's a gateway to allow the VMS systems to talk lpr over DECnet as
  107. long as you have a UNIX host that also speaks DECnet which can act as
  108. a gateway.
  109. X
  110. If you are running UNIX, you have to have a Berkeley-style TCP
  111. implementation on your machine (with socket(), bind() and that sort of
  112. stuff), and access to an Berkeley lpd server somewhere on the network.
  113. If you are running VMS, you can use either DEC's Ultrix connection or
  114. Wollongong WIN/TCP for VMS, or you can run lpr over DECnet.  The
  115. latter requires that you have access to a UNIX host that can speak
  116. DECnet (either SunLink DNI or DECnet-Ultrix), and which can talk to an
  117. lpr server somewhere.
  118. X
  119. At one time or another, I have tested the lpr program on SCO ODT 1.0,
  120. SunOS 4.1, Ultrix 3.x, Ultrix 4.x, 4.3 BSD, an IBM RS/6000 running AIX
  121. X3.x, and on a Stardent Titan running some variant of SysV.  It also
  122. works on VAX/VMS 5.4 with UCX TCP and DECnet.  (I got it to compile on
  123. a machine with an old version of WIN/TCP, but I couldn't fully test it
  124. because I don't have privileged access to that machine.)  The dnet-lpr
  125. gateway program has been tested on a Sun/3 running SunOS 4.1 and
  126. SunLink DNI 6.0, and a DecStation 5000 running Ultrix 4.2 and
  127. DECnet-Ultrix.
  128. X
  129. I have used SunOS and Ultrix machines as printer servers, but I would
  130. expect this program to work with any lpd server running 4.2BSD or
  131. X4.3BSD-derived code.
  132. X
  133. X* Warranty:
  134. X
  135. READ THIS BEFORE INSTALLING THIS CODE ON ANY MACHINE:
  136. X
  137. There is NO WARRANTY for this software, not even for merchantability
  138. nor for fitness for any particular purpose.  Anyone who installs or uses
  139. this software, does so entirely at his or her own risk.  The author
  140. will not be responsible for any ill consequences of the installation
  141. or use of this software, no matter how terrible.
  142. X
  143. X* Copyright, use and redistribution:
  144. X
  145. The source code for this program is Copyright 1990, 1991 by Keith Moore
  146. X
  147. Use of this program and distribution of the code in either source or
  148. compiled binary form are governed by the GNU General Public License, 
  149. Version 2.  See the file LICENSE for details.
  150. X
  151. X* Compiling on UNIX:
  152. X
  153. On many UNIX systems you can simply type "make".
  154. X
  155. On UNIX, if your C compiler does not define the macro "unix", add a
  156. X"CFLAGS=-Dunix" to the "make" command line, like so:
  157. X
  158. X    make CFLAGS=-Dunix
  159. X
  160. If you have SunLink DNI or DECnet-Ultrix and want to compile the
  161. decnet lpd gateway, type "make dnet-lpd-gw".
  162. X
  163. X* Compiling on VMS:
  164. X
  165. On VMS systems you need to edit the DESCRIP.MMS file first (assuming
  166. you have DEC/MMS), and pick which transport you want to use.  Also, be
  167. sure to select the proper object library.  Then type "mms" to make
  168. things.  If you use some other "make" clone besides DEC/MMS, then you
  169. may have to make small changes to the DESCRIP.MMS file and rename it
  170. to something like MAKEFILE.
  171. X
  172. If you don't have DEC/MMS or some flavor of "make", do the following:
  173. X
  174. cc/debug lpr.c
  175. cc/debug DRIVER.c
  176. link lpr,DRIVER,LIBRARY/lib
  177. X
  178. where DRIVER and LIBRARY are chosen from the following, based on whether
  179. you are using UCX TCP, Wollongong TCP, or DECnet:
  180. X
  181. Transport    DRIVER        LIBRARY
  182. UCX TCP        vms-ucx-tcp    sys$library:ucx$ipc.olb
  183. WIN/TCP        vms-win-tcp    twg$tcp:[netdist.lib]twglib.olb
  184. DECnet        vms-decnet    (not needed)
  185. X
  186. X* UNIX Installation:
  187. X
  188. On UNIX, "make install" should do the trick to install the lpr
  189. program.  (NOTE:: make install creates a set-uid program.  See below
  190. under IMPORTANT NOTES for details.)  You may have to edit the Makefile
  191. to change the installation directory.  Install the man page by hand,
  192. if your system supports these.  The file "lpr.cat" is a preformatted
  193. man page, in case your system does not support nroff.  If your system
  194. has a man command, you may be able to copy the lpr.cat file into an
  195. appropriate directory with an appropriate name so that "man lpr" will
  196. work.
  197. X
  198. lpr expects a file named /etc/LPD_SERVER that contains the host name
  199. of a machine that has a working BSD-style line printer daemon.
  200. XFailing this, it checks the environment variable LPD_SERVER for the
  201. printer server host, so users can override the system default.  Either
  202. of these can be manually overriden with the -S command line option.
  203. However the print server is specified, the client machine must have
  204. permission to print on the server's print queues.  Generally this is
  205. done by editing either /etc/hosts.lpd or /etc/hosts.equiv on the
  206. server.
  207. X
  208. X* VMS Installation:
  209. X
  210. To run lpr on VMS, copy LPR.EXE to an appropriate directory and define a 
  211. DCL symbol to point to it, e.g.:
  212. X
  213. lpr == "$some$system$directory:[some.sub.directory]lpr.exe"
  214. X
  215. You may need to install the image with privileges; see below.
  216. X
  217. after which it works almost, but not quite, just like on UNIX.
  218. Unfortunately, the VAX C library is really brain dead, so wildcards do
  219. not work, the entire command line is lower cased, and you can't have
  220. embedded spaces in file names.  (The effect of the last restriction is
  221. that you can't use lpr to print a file on a remote DECnet node if you
  222. don't have proxy access to that machine.)  If someone wants to
  223. contribute a CLD based front end for this program, I'll be happy to
  224. include it in a future release.
  225. X
  226. On VMS, the logical name LPD_SERVER must be defined to point to the
  227. name of the host acting as a print server (for TCP, this is the
  228. Internet domain name of the server; for DECnet, it's the DECnet node
  229. name of the machine where the gateway runs).  This can either be
  230. defined by the user or as a system-wide logical name.
  231. X
  232. To do the equivalent of lprm or lpq on VMS, define symbols like the
  233. following:
  234. X
  235. lpq == "$some$system$directory:[some.sub.directory]lpr.exe -showqueue"
  236. lprm == "$some$system$directory:[some.sub.directory]lpr.exe -remove"
  237. X
  238. X* Installation of the DECnet lpr gateway on SunOS:
  239. X
  240. X(You must be running SunLink DNI to do this:)
  241. X
  242. X"make install-gw" will install the dnet-lpd-gw program in an
  243. appropriate directory.  You might need to edit the Makefile, however,
  244. if /usr/sunlink/dni is not an appropriate directory on your machine.
  245. X"dnet-lpd-gw" is also installed set-uid to root.
  246. X
  247. The dnet-lpd-gw program should be installed so that it will be run
  248. with an remote DECnet client tries to connect to object 223.  On Sun
  249. systems, do this by editing the file /usr/sunlink/dni/dniserver.reg
  250. and adding a line like the following:
  251. X
  252. X223     DNETLPD /usr/sunlink/dni/dnet-lpd-gw
  253. X
  254. X(Currently, the number 223 is wired into vms-decnet.c.  This may
  255. change at some point.)  "make install-gw" will copy dnet-lpd-gw to the
  256. X/usr/sunlink/dni directory and install it with appropriate
  257. permissions.
  258. X
  259. X* Installation of the DECnet lpr gateway on Ultrix:
  260. X
  261. X(You have to be running DECnet-Ultrix to do this:)
  262. X
  263. Become root and use the "ncp" program to define the DNETLPD object as follows:
  264. X
  265. X# ncp
  266. ncp>clear object dnetlpd
  267. ncp>set object dnetlpd
  268. Number :  223
  269. XFile :  /usr/local/lib/dnet-lpd-gw
  270. Default User :  daemon
  271. Type :  sequenced packet
  272. Accept :  deferred
  273. ncp> ^D
  274. X
  275. X(Note: you can set the "default user" to "root" instead of "daemon",
  276. in which case dnet-lpd-gw need not be set-uid to root.  The set-uid
  277. approach is probably safer in this case.)
  278. X
  279. X* IMPORTANT NOTES: 
  280. X
  281. On UNIX, the program is installed set-uid to root, which is necessary
  282. so that lpr can bind to a privileged TCP port.  This should not
  283. present a security risk since the first thing that the program does is
  284. to create the socket and bind it to the privileged port, after which
  285. it immediately disables its special privileges.  All file opens,
  286. reads, etc., are then done with the invoking user's normal privileges.
  287. X
  288. On VMS, similar concerns apply if using TCP -- the program must be
  289. installed as a privileged image with the INSTALL utility.  UCX TCP
  290. requires either BYPASS or SYSPRV privilege in order to allow lpr to
  291. bind to a privileged port.  I'm not sure offhand what privileges
  292. WIN/TCP requires.  Anyway, immediately after successfully binding to a
  293. privileged port, the lpr program turns off all image-installed
  294. privileges.
  295. X
  296. XFor VMS systems using a DECnet-based lpr, no special installation is
  297. required, but the UNIX-based server does have to be installed set-uid
  298. to root.  If when using lpr over DECnet you get the message "your host
  299. does not have line printer access", you need to put "localhost" or the
  300. hostname of the print server in the print server machine's
  301. X/etc/hosts.lpd file.  You may then have to kill and restart lpd on the
  302. server to get it to recognize the changed /etc/hosts.lpd file.
  303. X
  304. X* Miscellaneous:
  305. X
  306. The UNIX Makefile has rules to generate this package in various
  307. formats to allow it to be moved from system to system.  Of special
  308. interest is the rule for "make port-lpr.vms", which creates a VMS .COM
  309. file that extracts itself when run in an empty VMS directory.
  310. X
  311. Sorry, there's no special HELP file for lpr on VMS.  Perhaps someone
  312. will contribute one.
  313. X
  314. If you find bugs and can supply fixes, please let me know and I'll try
  315. and have the fixes incorporated into a future release.
  316. X
  317. Keith Moore
  318. moore@cs.utk.edu
  319. END_OF_FILE
  320. if test 9221 -ne `wc -c <'README'`; then
  321.     echo shar: \"'README'\" unpacked with wrong size!
  322. fi
  323. # end of 'README'
  324. fi
  325. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  326.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  327. else
  328. echo shar: Extracting \"'MANIFEST'\" \(809 characters\)
  329. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  330. README - general information file
  331. MANIFEST - this file
  332. LICENSE - GNU General Public License, Version 1, which applies to this source
  333. ChangeLog - history of source changes
  334. lpr.c - main program
  335. config.h - trivial config file.
  336. Makefile - you do use make, don't you?
  337. unix-tcp.c - back-end interface for UNIX systems with BSD socket libraries
  338. vms-ucx-tcp.c - back-end interface for VMS systems with UCX tcp
  339. vms-win-tcp.c - back-end interface for VMS systems with Wollongong WIN/TCP
  340. vms-decnet.c - back-end interface for VMS systems using DECnet-VAX
  341. descrip.mms - Makefile for VMS systems using DEC/MMS
  342. dnet-lpd-gw.c - UNIX program that gateways DECnet-based lpr to the local
  343. X            print spooler
  344. lpr.man - {n,t}roff source for lpr man page
  345. lpr.cat - preformatted man page for those systems that don't have nroff
  346. END_OF_FILE
  347. if test 809 -ne `wc -c <'MANIFEST'`; then
  348.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  349. fi
  350. # end of 'MANIFEST'
  351. fi
  352. if test -f 'LICENSE' -a "${1}" != "-c" ; then 
  353.   echo shar: Will not clobber existing file \"'LICENSE'\"
  354. else
  355. echo shar: Extracting \"'LICENSE'\" \(17982 characters\)
  356. sed "s/^X//" >'LICENSE' <<'END_OF_FILE'
  357. X            GNU GENERAL PUBLIC LICENSE
  358. X               Version 2, June 1991
  359. X
  360. X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  361. X                          675 Mass Ave, Cambridge, MA 02139, USA
  362. X Everyone is permitted to copy and distribute verbatim copies
  363. X of this license document, but changing it is not allowed.
  364. X
  365. X                Preamble
  366. X
  367. X  The licenses for most software are designed to take away your
  368. freedom to share and change it.  By contrast, the GNU General Public
  369. License is intended to guarantee your freedom to share and change free
  370. software--to make sure the software is free for all its users.  This
  371. General Public License applies to most of the Free Software
  372. XFoundation's software and to any other program whose authors commit to
  373. using it.  (Some other Free Software Foundation software is covered by
  374. the GNU Library General Public License instead.)  You can apply it to
  375. your programs, too.
  376. X
  377. X  When we speak of free software, we are referring to freedom, not
  378. price.  Our General Public Licenses are designed to make sure that you
  379. have the freedom to distribute copies of free software (and charge for
  380. this service if you wish), that you receive source code or can get it
  381. if you want it, that you can change the software or use pieces of it
  382. in new free programs; and that you know you can do these things.
  383. X
  384. X  To protect your rights, we need to make restrictions that forbid
  385. anyone to deny you these rights or to ask you to surrender the rights.
  386. These restrictions translate to certain responsibilities for you if you
  387. distribute copies of the software, or if you modify it.
  388. X
  389. X  For example, if you distribute copies of such a program, whether
  390. gratis or for a fee, you must give the recipients all the rights that
  391. you have.  You must make sure that they, too, receive or can get the
  392. source code.  And you must show them these terms so they know their
  393. rights.
  394. X
  395. X  We protect your rights with two steps: (1) copyright the software, and
  396. X(2) offer you this license which gives you legal permission to copy,
  397. distribute and/or modify the software.
  398. X
  399. X  Also, for each author's protection and ours, we want to make certain
  400. that everyone understands that there is no warranty for this free
  401. software.  If the software is modified by someone else and passed on, we
  402. want its recipients to know that what they have is not the original, so
  403. that any problems introduced by others will not reflect on the original
  404. authors' reputations.
  405. X
  406. X  Finally, any free program is threatened constantly by software
  407. patents.  We wish to avoid the danger that redistributors of a free
  408. program will individually obtain patent licenses, in effect making the
  409. program proprietary.  To prevent this, we have made it clear that any
  410. patent must be licensed for everyone's free use or not licensed at all.
  411. X
  412. X  The precise terms and conditions for copying, distribution and
  413. modification follow.
  414. X
  415. X            GNU GENERAL PUBLIC LICENSE
  416. X   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  417. X
  418. X  0. This License applies to any program or other work which contains
  419. a notice placed by the copyright holder saying it may be distributed
  420. under the terms of this General Public License.  The "Program", below,
  421. refers to any such program or work, and a "work based on the Program"
  422. means either the Program or any derivative work under copyright law:
  423. that is to say, a work containing the Program or a portion of it,
  424. either verbatim or with modifications and/or translated into another
  425. language.  (Hereinafter, translation is included without limitation in
  426. the term "modification".)  Each licensee is addressed as "you".
  427. X
  428. Activities other than copying, distribution and modification are not
  429. covered by this License; they are outside its scope.  The act of
  430. running the Program is not restricted, and the output from the Program
  431. is covered only if its contents constitute a work based on the
  432. Program (independent of having been made by running the Program).
  433. Whether that is true depends on what the Program does.
  434. X
  435. X  1. You may copy and distribute verbatim copies of the Program's
  436. source code as you receive it, in any medium, provided that you
  437. conspicuously and appropriately publish on each copy an appropriate
  438. copyright notice and disclaimer of warranty; keep intact all the
  439. notices that refer to this License and to the absence of any warranty;
  440. and give any other recipients of the Program a copy of this License
  441. along with the Program.
  442. X
  443. You may charge a fee for the physical act of transferring a copy, and
  444. you may at your option offer warranty protection in exchange for a fee.
  445. X
  446. X  2. You may modify your copy or copies of the Program or any portion
  447. of it, thus forming a work based on the Program, and copy and
  448. distribute such modifications or work under the terms of Section 1
  449. above, provided that you also meet all of these conditions:
  450. X
  451. X    a) You must cause the modified files to carry prominent notices
  452. X    stating that you changed the files and the date of any change.
  453. X
  454. X    b) You must cause any work that you distribute or publish, that in
  455. X    whole or in part contains or is derived from the Program or any
  456. X    part thereof, to be licensed as a whole at no charge to all third
  457. X    parties under the terms of this License.
  458. X
  459. X    c) If the modified program normally reads commands interactively
  460. X    when run, you must cause it, when started running for such
  461. X    interactive use in the most ordinary way, to print or display an
  462. X    announcement including an appropriate copyright notice and a
  463. X    notice that there is no warranty (or else, saying that you provide
  464. X    a warranty) and that users may redistribute the program under
  465. X    these conditions, and telling the user how to view a copy of this
  466. X    License.  (Exception: if the Program itself is interactive but
  467. X    does not normally print such an announcement, your work based on
  468. X    the Program is not required to print an announcement.)
  469. X
  470. These requirements apply to the modified work as a whole.  If
  471. identifiable sections of that work are not derived from the Program,
  472. and can be reasonably considered independent and separate works in
  473. themselves, then this License, and its terms, do not apply to those
  474. sections when you distribute them as separate works.  But when you
  475. distribute the same sections as part of a whole which is a work based
  476. on the Program, the distribution of the whole must be on the terms of
  477. this License, whose permissions for other licensees extend to the
  478. entire whole, and thus to each and every part regardless of who wrote it.
  479. X
  480. Thus, it is not the intent of this section to claim rights or contest
  481. your rights to work written entirely by you; rather, the intent is to
  482. exercise the right to control the distribution of derivative or
  483. collective works based on the Program.
  484. X
  485. In addition, mere aggregation of another work not based on the Program
  486. with the Program (or with a work based on the Program) on a volume of
  487. a storage or distribution medium does not bring the other work under
  488. the scope of this License.
  489. X
  490. X  3. You may copy and distribute the Program (or a work based on it,
  491. under Section 2) in object code or executable form under the terms of
  492. Sections 1 and 2 above provided that you also do one of the following:
  493. X
  494. X    a) Accompany it with the complete corresponding machine-readable
  495. X    source code, which must be distributed under the terms of Sections
  496. X    1 and 2 above on a medium customarily used for software interchange; or,
  497. X
  498. X    b) Accompany it with a written offer, valid for at least three
  499. X    years, to give any third party, for a charge no more than your
  500. X    cost of physically performing source distribution, a complete
  501. X    machine-readable copy of the corresponding source code, to be
  502. X    distributed under the terms of Sections 1 and 2 above on a medium
  503. X    customarily used for software interchange; or,
  504. X
  505. X    c) Accompany it with the information you received as to the offer
  506. X    to distribute corresponding source code.  (This alternative is
  507. X    allowed only for noncommercial distribution and only if you
  508. X    received the program in object code or executable form with such
  509. X    an offer, in accord with Subsection b above.)
  510. X
  511. The source code for a work means the preferred form of the work for
  512. making modifications to it.  For an executable work, complete source
  513. code means all the source code for all modules it contains, plus any
  514. associated interface definition files, plus the scripts used to
  515. control compilation and installation of the executable.  However, as a
  516. special exception, the source code distributed need not include
  517. anything that is normally distributed (in either source or binary
  518. form) with the major components (compiler, kernel, and so on) of the
  519. operating system on which the executable runs, unless that component
  520. itself accompanies the executable.
  521. X
  522. If distribution of executable or object code is made by offering
  523. access to copy from a designated place, then offering equivalent
  524. access to copy the source code from the same place counts as
  525. distribution of the source code, even though third parties are not
  526. compelled to copy the source along with the object code.
  527. X
  528. X  4. You may not copy, modify, sublicense, or distribute the Program
  529. except as expressly provided under this License.  Any attempt
  530. otherwise to copy, modify, sublicense or distribute the Program is
  531. void, and will automatically terminate your rights under this License.
  532. However, parties who have received copies, or rights, from you under
  533. this License will not have their licenses terminated so long as such
  534. parties remain in full compliance.
  535. X
  536. X  5. You are not required to accept this License, since you have not
  537. signed it.  However, nothing else grants you permission to modify or
  538. distribute the Program or its derivative works.  These actions are
  539. prohibited by law if you do not accept this License.  Therefore, by
  540. modifying or distributing the Program (or any work based on the
  541. Program), you indicate your acceptance of this License to do so, and
  542. all its terms and conditions for copying, distributing or modifying
  543. the Program or works based on it.
  544. X
  545. X  6. Each time you redistribute the Program (or any work based on the
  546. Program), the recipient automatically receives a license from the
  547. original licensor to copy, distribute or modify the Program subject to
  548. these terms and conditions.  You may not impose any further
  549. restrictions on the recipients' exercise of the rights granted herein.
  550. You are not responsible for enforcing compliance by third parties to
  551. this License.
  552. X
  553. X  7. If, as a consequence of a court judgment or allegation of patent
  554. infringement or for any other reason (not limited to patent issues),
  555. conditions are imposed on you (whether by court order, agreement or
  556. otherwise) that contradict the conditions of this License, they do not
  557. excuse you from the conditions of this License.  If you cannot
  558. distribute so as to satisfy simultaneously your obligations under this
  559. License and any other pertinent obligations, then as a consequence you
  560. may not distribute the Program at all.  For example, if a patent
  561. license would not permit royalty-free redistribution of the Program by
  562. all those who receive copies directly or indirectly through you, then
  563. the only way you could satisfy both it and this License would be to
  564. refrain entirely from distribution of the Program.
  565. X
  566. If any portion of this section is held invalid or unenforceable under
  567. any particular circumstance, the balance of the section is intended to
  568. apply and the section as a whole is intended to apply in other
  569. circumstances.
  570. X
  571. It is not the purpose of this section to induce you to infringe any
  572. patents or other property right claims or to contest validity of any
  573. such claims; this section has the sole purpose of protecting the
  574. integrity of the free software distribution system, which is
  575. implemented by public license practices.  Many people have made
  576. generous contributions to the wide range of software distributed
  577. through that system in reliance on consistent application of that
  578. system; it is up to the author/donor to decide if he or she is willing
  579. to distribute software through any other system and a licensee cannot
  580. impose that choice.
  581. X
  582. This section is intended to make thoroughly clear what is believed to
  583. be a consequence of the rest of this License.
  584. X
  585. X  8. If the distribution and/or use of the Program is restricted in
  586. certain countries either by patents or by copyrighted interfaces, the
  587. original copyright holder who places the Program under this License
  588. may add an explicit geographical distribution limitation excluding
  589. those countries, so that distribution is permitted only in or among
  590. countries not thus excluded.  In such case, this License incorporates
  591. the limitation as if written in the body of this License.
  592. X
  593. X  9. The Free Software Foundation may publish revised and/or new versions
  594. of the General Public License from time to time.  Such new versions will
  595. be similar in spirit to the present version, but may differ in detail to
  596. address new problems or concerns.
  597. X
  598. XEach version is given a distinguishing version number.  If the Program
  599. specifies a version number of this License which applies to it and "any
  600. later version", you have the option of following the terms and conditions
  601. either of that version or of any later version published by the Free
  602. Software Foundation.  If the Program does not specify a version number of
  603. this License, you may choose any version ever published by the Free Software
  604. XFoundation.
  605. X
  606. X  10. If you wish to incorporate parts of the Program into other free
  607. programs whose distribution conditions are different, write to the author
  608. to ask for permission.  For software which is copyrighted by the Free
  609. Software Foundation, write to the Free Software Foundation; we sometimes
  610. make exceptions for this.  Our decision will be guided by the two goals
  611. of preserving the free status of all derivatives of our free software and
  612. of promoting the sharing and reuse of software generally.
  613. X
  614. X                NO WARRANTY
  615. X
  616. X  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
  617. XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
  618. OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
  619. PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
  620. OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  621. MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
  622. TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
  623. PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  624. REPAIR OR CORRECTION.
  625. X
  626. X  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  627. WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
  628. REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  629. INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
  630. OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
  631. TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
  632. YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  633. PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  634. POSSIBILITY OF SUCH DAMAGES.
  635. X
  636. X             END OF TERMS AND CONDITIONS
  637. X
  638. X    Appendix: How to Apply These Terms to Your New Programs
  639. X
  640. X  If you develop a new program, and you want it to be of the greatest
  641. possible use to the public, the best way to achieve this is to make it
  642. free software which everyone can redistribute and change under these terms.
  643. X
  644. X  To do so, attach the following notices to the program.  It is safest
  645. to attach them to the start of each source file to most effectively
  646. convey the exclusion of warranty; and each file should have at least
  647. the "copyright" line and a pointer to where the full notice is found.
  648. X
  649. X    <one line to give the program's name and a brief idea of what it does.>
  650. X    Copyright (C) 19yy  <name of author>
  651. X
  652. X    This program is free software; you can redistribute it and/or modify
  653. X    it under the terms of the GNU General Public License as published by
  654. X    the Free Software Foundation; either version 2 of the License, or
  655. X    (at your option) any later version.
  656. X
  657. X    This program is distributed in the hope that it will be useful,
  658. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  659. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  660. X    GNU General Public License for more details.
  661. X
  662. X    You should have received a copy of the GNU General Public License
  663. X    along with this program; if not, write to the Free Software
  664. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  665. X
  666. Also add information on how to contact you by electronic and paper mail.
  667. X
  668. If the program is interactive, make it output a short notice like this
  669. when it starts in an interactive mode:
  670. X
  671. X    Gnomovision version 69, Copyright (C) 19yy name of author
  672. X    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
  673. X    This is free software, and you are welcome to redistribute it
  674. X    under certain conditions; type `show c' for details.
  675. X
  676. The hypothetical commands `show w' and `show c' should show the appropriate
  677. parts of the General Public License.  Of course, the commands you use may
  678. be called something other than `show w' and `show c'; they could even be
  679. mouse-clicks or menu items--whatever suits your program.
  680. X
  681. You should also get your employer (if you work as a programmer) or your
  682. school, if any, to sign a "copyright disclaimer" for the program, if
  683. necessary.  Here is a sample; alter the names:
  684. X
  685. X  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  686. X  `Gnomovision' (which makes passes at compilers) written by James Hacker.
  687. X
  688. X  <signature of Ty Coon>, 1 April 1989
  689. X  Ty Coon, President of Vice
  690. X
  691. This General Public License does not permit incorporating your program into
  692. proprietary programs.  If your program is a subroutine library, you may
  693. consider it more useful to permit linking proprietary applications with the
  694. library.  If this is what you want to do, use the GNU Library General
  695. Public License instead of this License.
  696. END_OF_FILE
  697. if test 17982 -ne `wc -c <'LICENSE'`; then
  698.     echo shar: \"'LICENSE'\" unpacked with wrong size!
  699. fi
  700. # end of 'LICENSE'
  701. fi
  702. if test -f 'ChangeLog' -a "${1}" != "-c" ; then 
  703.   echo shar: Will not clobber existing file \"'ChangeLog'\"
  704. else
  705. echo shar: Extracting \"'ChangeLog'\" \(8268 characters\)
  706. sed "s/^X//" >'ChangeLog' <<'END_OF_FILE'
  707. Thu May 21 01:30:35 1992  Keith Moore  (moore@wilma)
  708. X
  709. X    * compiled and tested decnet gw code on ultrix.  Quickly tried
  710. X      to fix bogus error codes on vms and generally failed.
  711. X
  712. X    * README: corrected/updated to reflect more recent changes
  713. X
  714. X    * LICENSE: is now GPLv2
  715. X
  716. X    * lpr.man: known bug list updated.
  717. X
  718. X    * patchlevel.h: updated minor version (patchlevel) to 4, because
  719. X      I had released container files with version 1.2 and 1.3.  New
  720. X      container files will be version 1.4.
  721. X
  722. Thu Dec 12 01:03:55 1991  Keith Moore  (moore at wilma)
  723. X
  724. X    * lpr.c (append_string_to_buffer, read_file_into_buffer):
  725. X      made them return a pointer to the buffer, in case realloc()
  726. X      (in enlarge_buffer()) had to move the buffer somewhere else.
  727. X    
  728. X    * lpr.c (control): reassign job->cfile to the value returned
  729. X      from append_string_to_buffer()
  730. X
  731. X    * lpr.c (send_print_file): respect return value from
  732. X      read_file_into_buffer()
  733. X
  734. X      (lpr now accepts large files from stdin again)
  735. X
  736. Wed Dec  4 00:42:58 1991  Keith Moore  (moore at wilma)
  737. X
  738. X    * unix-tcp.c, vms-decnet.c, vms-ucx-tcp.c: fix typo in error
  739. X      msg.
  740. X
  741. X    * lpr.c (lprm): Initialize remove_all flag to zero.
  742. X      Fix the case where no args are supplied.
  743. X
  744. X    * lpr.c (get_lpd_server): add check in case fscanf() fails.
  745. X      (could happen if file is empty)  Cast return value to
  746. X      (char *) to placate fussy DEC compiler.
  747. X
  748. Thu Sep 12 23:54:29 1991  Keith Moore  (moore at wilma)
  749. X
  750. X    * lpr.c (get_lpd_server): new function
  751. X
  752. X    * lpr and friends now look for a file named /etc/LPD_SERVER to
  753. X      get the default printer server.  Or you can still specify
  754. X      -S printer-server on the command-line.
  755. X
  756. XFri Sep  6 12:22:09 1991  Keith Moore  (moore at wilma)
  757. X
  758. X    * [various tcp modules] (get_priv_tcp_socket):
  759. X      if all attempts to bind to a privileged port fail, close socket
  760. X      and return EOF.
  761. X
  762. Thu Jul 25 00:34:06 1991  Keith Moore  (moore at chili)
  763. X
  764. X
  765. X        file lpr.c:
  766. X
  767. X    * add lpq and lprm functions: if argv[0] ends
  768. X      in "lpq" or "lprm", behave like those commands.  Also
  769. X      add -showqueue and -remove options for use on VMS.
  770. X
  771. X      (real_option):
  772. X    * -f now means "print a FORTRAN output file"
  773. X    * -r now means "remove file after spooling" - it was being
  774. X      construed as "print a FORTRAN output file" because the
  775. X      lpd protocol command to do this is 'r'.
  776. X    * added -S option to specify printer server.
  777. X
  778. X      (guess_file_type)
  779. X    * Don't print a message when we realize it's a PostScript
  780. X      file, because there's no special command-line option for
  781. X      these.
  782. X
  783. X      (dump_buf)
  784. X    * mask each byte with 0xff before printing in octal.
  785. X    * Also format output a little nicer.
  786. X
  787. X    file lpr.man:
  788. X
  789. X    * change text regarding -f and -r options;
  790. X      remove a diagnostic message that is no longer used
  791. X      (still need to document lprm, lpq, and
  792. X      -remove, -showqueue options)
  793. X
  794. X    files unix-tcp.c,vms-win-tcp.c,vms-ucx-tcp.c:
  795. X
  796. X      (gethostbynameoraddr) 
  797. X        * added new function.
  798. X      if hostname argument begins with a digit, it is assumed to be
  799. X      an IP address, and gethostbynameoraddr() will simply fill in the
  800. X      correct fields in the hostent structure without doing an address
  801. X      lookup.  Otherwise it returns the result of gethostbyname()
  802. X
  803. X    * in open_lpd(), call gethostbynameoraddr() to get IP address
  804. X
  805. X
  806. Thu May  9 19:26:30 1991  Keith Moore  (moore at chili)
  807. X
  808. X    * lpr.c: make a more informative error message when remote
  809. X      server refuses to accept a print job.
  810. X
  811. X    * vms-ucx-tcp.c, vms-win-tcp.c, unix-tcp.c (get_priv_tcp_socket):
  812. X      don't exit, just give warning if EACCES error occurs trying to 
  813. X          bind to privileged port -- some lpd's don't require this anyway.
  814. X
  815. XFri Apr 12 16:57:13 1991  Keith Moore  (moore at chili)
  816. X
  817. X    * README: added some additional instructions for compiling
  818. X      on VMS.
  819. X
  820. X    * Makefile: fixed rule for port-lpr.vms that was always
  821. X      appending the new archive onto an existing port-lpr.vms
  822. X      file.
  823. X
  824. Tue Apr  9 21:16:31 1991  Keith Moore  (moore at chili)
  825. X
  826. X        * released as version 1.1
  827. X
  828. X    * lpr.man: picked up some nits.
  829. X
  830. Tue Apr  9 20:37:40 1991  Keith Moore  (moore at chili)
  831. X
  832. X    * Makefile (clean): do "rm -f" instead of "rm"
  833. X
  834. X    * dnet-lpd-gw.c (accept_decnet_connection):
  835. X      added support for DECnet-Ultrix.  Fixed typo that was setting
  836. X      DECnet_remoteNode to the name of the remote user.
  837. X
  838. X    * README: add notes about DECnet-Ultrix support for gateway.
  839. X
  840. X    * BLURB: new file - capsule description of package.
  841. X
  842. Sat Mar 30 02:04:45 1991  Keith Moore  (moore at chili)
  843. X
  844. X    * lpr.man, README, MANIFEST - updated
  845. X
  846. X    * descrip.mms: makefile for vms - created
  847. X
  848. X    * Makefile: updated to reflect new changes, and also to
  849. X      create a simple shar file for VMS
  850. X
  851. X    * dnet-lpd-gw.c - new program - gateway lpr over DECnet to
  852. X      a TCP-based lpr daemon.
  853. X
  854. X    * vms-decnet.c - new module - send lpr protocol over DECnet
  855. X      instead of TCP.
  856. X
  857. X    * vms-*.c - translate_logical_name(), get_decnet_node_name()
  858. X      new functions.  Use translate_logical_name() instead of getenv()
  859. X      to prevent spoofing of important logical names.
  860. X
  861. X    * vms-*.c, unix-tcp.c - add support for MAKE_EMAIL_ADDRESS macro to
  862. X      override default way of sending mail to whomever submitted the job.
  863. X
  864. X    * TO DO:
  865. X      add ultrix support for dnet-lpd-gw.c
  866. X      add authentication to dnet-lpd-gw.c
  867. X      The email address hacks don't work -- even if the client tells
  868. X      the server that the user's email address is terre.dnet.utk.edu,
  869. X      the server still sends mail to simply "user@terre" on job 
  870. X      completion.  Fix this somehow.
  871. X
  872. XFri Mar 29 14:54:51 1991  Keith Moore  (moore at chili)
  873. X
  874. X    * unix-tcp.c, vms-ucx-tcp.c, vms-win-tcp.c (open_lpd):
  875. X      changed to accept an argument to open_lpd specifying
  876. X      what host to use as a printer server.
  877. X
  878. X    * lpr.c: changed called to open_lpd to pass host name of
  879. X      printer server as an argument, rather than implicitly
  880. X      through the variable lpd_server.
  881. X
  882. X    * makefile.vms: new makefile for VMS make, or some reasonable
  883. X      facsimile thereof
  884. X
  885. X    * config.h: We don't really need this anymore to specify which
  886. X      kind of tcp/decnet we are using, but we do need it to specify
  887. X      things like how to generate the user's email address back to
  888. X      a VMS machine...definitely a site-specific option.
  889. X
  890. X    * extracted network- and system-specific code into separate
  891. X      modules: unix-tcp.c, vms-ucx-tcp.c, and vms-decnet.c
  892. X
  893. X    * lpr.c (main) Was redeclaring the printer environment
  894. X      variable, thus any -P printer option was not working.
  895. X
  896. X    * lpr.c (option) Fixed bug in option parsing.  I was using
  897. X      strchr (opt, "P#CJTi1234w") to see if the opt character
  898. X      was in that set of characters.  The arguments should have been
  899. X      reversed -- now they are.  Also, "opt" should have been "opt[1]"
  900. X      Also added 'q' to that set, so -q printer will work.  (This is
  901. X      for VMS, which lower-cases all command-line arguments unless you
  902. X      put them in quotes.)
  903. X
  904. X    * TO DO:
  905. X      On vms, expand wildcard filenames (yuk!)
  906. X      Build alternate argument parser for VMS.
  907. X      Make sure we print out any error messages returned from server.
  908. X
  909. X
  910. Thu Mar 28 16:30:09 1991  Keith Moore  (moore at chili)
  911. X
  912. X    * if a host has multiple IP addresses, attempt to connect to
  913. X      each of them before giving up.  If debug is set, print out
  914. X      each IP address as we try it.
  915. X
  916. X    * converted to "Classic" (non-ANSI) C (Yuk!).  GNU cc doesn't let
  917. X      us pass a struct in_addr to inet_ntoa() because of differences
  918. X      between argument passing conventions between gcc and the system-
  919. X      supplied cc (with which the inet_ntoa() routine was compiled).
  920. X      (At least this is true on a SPARC running SunOS 4.1.1)
  921. X
  922. X    * added code to let lpr run on VMS with UCX TCP.
  923. X
  924. Tue Mar 26 21:53:52 1991  Keith Moore  (moore at chili)
  925. X
  926. X    * lpr.c (sysdep): call endpwent() after calling getpwuid() just
  927. X      to make sure the file descriptor for /etc/passwd is closed.
  928. X      (This is just paranoia-for-security - we don't exec anything
  929. X      anyway, so there's no way for some program to inherit that file
  930. X      descriptor.)
  931. X
  932. X    * lpr.c (real_option): add newline after version info when -debug
  933. X      is set
  934. X
  935. X    * README: add note about compiling, and that this works on an
  936. X      IBM RS/6000 running AIX.
  937. X
  938. Thu Mar 21 19:50:34 1991  Keith Moore  (moore at chili)
  939. X
  940. X    * packaged this up and sent it out as version 1.0
  941. X
  942. X    * if "printer" is not defined in /etc/services, just assume that
  943. X      we want to use port 515.
  944. X
  945. X    * wrote a man page and README.
  946. X
  947. X    * added a note referencing the GNU General Public License.
  948. X
  949. END_OF_FILE
  950. if test 8268 -ne `wc -c <'ChangeLog'`; then
  951.     echo shar: \"'ChangeLog'\" unpacked with wrong size!
  952. fi
  953. # end of 'ChangeLog'
  954. fi
  955. if test -f 'lpr.c' -a "${1}" != "-c" ; then 
  956.   echo shar: Will not clobber existing file \"'lpr.c'\"
  957. else
  958. echo shar: Extracting \"'lpr.c'\" \(25058 characters\)
  959. sed "s/^X//" >'lpr.c' <<'END_OF_FILE'
  960. X/*
  961. X * "lpr" program for systems that don't have lpd but can talk to a system
  962. X * that does using TCP or DECnet
  963. X *
  964. X * Copyright (C) 1990, 1991 Keith Moore
  965. X
  966. X * This program is free software; you can redistribute it and/or modify
  967. X * it under the terms of the GNU General Public License, Version 1,
  968. X * as published by the Free Software Foundation.
  969. X *
  970. X * This program is distributed in the hope that it will be useful,
  971. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  972. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  973. X * GNU General Public License for more details.
  974. X *
  975. X * You should have received a copy of the GNU General Public License
  976. X * along with this program; if not, write to the Free Software
  977. X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  978. X *
  979. X * Written by Keith Moore, December 1990
  980. X * Email: moore@cs.utk.edu (Internet)    moore@utkvx (BITNET)
  981. X * Snail: Box 16320 / Knoxville TN  37996 / USA
  982. X */
  983. X
  984. X/* TO DO:
  985. X * - send troff font names
  986. X * - add support for /etc/printcap files.
  987. X * - special hacks for Imagen and/or PostScript printers (maybe)
  988. X * - support -i (indent) and -w (page width) options
  989. X * - handle huge files too big to read into memory (UNIX systems only)
  990. X * - recognize ditroff, raster, cifplot, and FORTRAN output files (maybe)
  991. X * - handle multiple lpd servers -- try each until we find one that's up.
  992. X * - allow printer names of the form printer@host or host::printer,
  993. X * - add an option to specify job-id (for use when using this program
  994. X *   as the back-end to another print spooling system -- you can keep the
  995. X *   job-ids the same on both systems if you're lucky).
  996. X * - add an option to wait until the job is actually printed -- this is
  997. X *   not easy to do but is very useful when this program is being used
  998. X *   as the back-end to another kind of print spooler.
  999. X */
  1000. X
  1001. X/*
  1002. X * #define MAIN_PROGRAM here so common.h will allocate storage for the
  1003. X * variables defined there instead of making them external references.
  1004. X */
  1005. X
  1006. X#define MAIN_PROGRAM
  1007. X#include "config.h"
  1008. X#include "common.h"
  1009. X#include "patchlevel.h"
  1010. X#include <stdio.h>
  1011. X#include <ctype.h>
  1012. X
  1013. X#ifdef unix
  1014. X#include <sys/types.h>
  1015. X#include <sys/stat.h>
  1016. X#define EXIT_OK 0
  1017. X#define EXIT_FAIL 1
  1018. X#endif
  1019. X
  1020. X#ifdef vms
  1021. X#include <types.h>
  1022. X#include <stat.h>
  1023. X#define EXIT_OK 0
  1024. X#define EXIT_FAIL 2
  1025. X#endif
  1026. X
  1027. X#define VERSION 1
  1028. X
  1029. X/*
  1030. X * options...not all of which are supported
  1031. X */
  1032. char *printer;            /* name of remote print queue */
  1033. char *lpd_server;        /* name of the remote printer server */
  1034. char file_type = '?';        /* kind of file to be printed */
  1035. char *title = NULL;        /* page headings for pr */
  1036. char *jobtitle = NULL;        /* job name */
  1037. char *jobclass = NULL;        /* job class */
  1038. int num_copies = 1;        /* number of copies to print */
  1039. int indent = 0;            /* # of spaces to indent */
  1040. int page_width = 72;        /* page width for pr */
  1041. char *fontnames[4];        /* names of troff fonts */
  1042. int lflag = 0;            /* if lpq, list in long format */
  1043. int rflag = 0;            /* if 1, remove file after spooling */
  1044. int mflag = 0;            /* if 1, send mail on completion */
  1045. int hflag = 0;            /* if 1, omit burst page */
  1046. X
  1047. X/* debug option flag is declared in common.h */
  1048. X
  1049. X#define min(a,b) ((a) < (b) ? (a) : (b))
  1050. char *getenv ();
  1051. char *calloc ();
  1052. char *realloc ();
  1053. char *strrchr ();
  1054. X
  1055. X/*
  1056. X * debugging routines
  1057. X */
  1058. X
  1059. void
  1060. dump_buf (fp, prefix, buf, size)
  1061. XFILE *fp; char *prefix; char *buf; unsigned size;
  1062. X{
  1063. X    if (size > 0)
  1064. X    fprintf (fp, "%s", prefix);
  1065. X    while (size > 0){
  1066. X        if (*buf >= ' ' && *buf <= '~')
  1067. X            putc (*buf, fp);
  1068. X        else if (*buf == '\n') {
  1069. X            fprintf (fp, "\\n");
  1070. X        if (size > 1)
  1071. X        fprintf (fp, "\n%*s", strlen (prefix), "");
  1072. X    }
  1073. X    else
  1074. X            fprintf (fp, "\\%03o", *buf & 0xff);
  1075. X        ++buf;
  1076. X        --size;
  1077. X    }
  1078. X    fprintf (fp, "\n");
  1079. X}
  1080. X
  1081. X
  1082. int
  1083. x_read (fd, buf, size)
  1084. int fd; char *buf; unsigned size;
  1085. X{
  1086. X    int nread = read (fd, (char *) buf, size);
  1087. X    if (debug)
  1088. X    dump_buf (stderr, "<<<", buf, nread);
  1089. X    return nread;
  1090. X}
  1091. X
  1092. int
  1093. x_write (fd, buf, size)
  1094. int fd; char *buf; unsigned size;
  1095. X{
  1096. X    if (debug)
  1097. X    dump_buf (stderr, ">>>", buf, size);
  1098. X    return write (fd, (char *) buf, size);
  1099. X}
  1100. X
  1101. int
  1102. y_write (fd, buf, size)
  1103. int fd; char *buf; unsigned size;
  1104. X{
  1105. X    if (debug)
  1106. X    fprintf (stderr, ">>> (%d bytes)\n", size);
  1107. X    return write (fd, (char *) buf, size);
  1108. X}
  1109. X
  1110. X
  1111. X/*
  1112. X * parse an option with an optional argument (which may be NULL)
  1113. X * return 1 if optional argument used, else 0
  1114. X * (one of these days I'll start using getopt())
  1115. X */
  1116. int
  1117. real_option (opt, arg)
  1118. char *opt; char *arg;
  1119. X{
  1120. X    if (opt[1] && opt[2] == '\0') {
  1121. X    /* single letter options */
  1122. X    switch (opt[1]) {
  1123. X        /*
  1124. X         * file types
  1125. X         */
  1126. X    case 'l':        /* text file with embedded control chars */
  1127. X        file_type = 'l';
  1128. X        lflag++;        /* or -l (long) option for lpq */
  1129. X        return 0;
  1130. X    case 'f':        /* Fortran output file with carraige control */
  1131. X        file_type = 'r';
  1132. X        return 0;
  1133. X    case 'c':        /* cifplot (Caltech Intermediate Form) file */
  1134. X    case 'd':        /* TeX .dvi file */
  1135. X    case 'g':        /* UNIX plot file */
  1136. X    case 'n':        /* ditroff output file */
  1137. X    case 'o':        /* PostScript file ??? */
  1138. X    case 'p':        /* text file (add page headers using pr) */
  1139. X    case 't':        /* C/A/T troff output file*/
  1140. X    case 'v':        /* Versatec output file */
  1141. X        file_type = opt[1];
  1142. X        return 0;
  1143. X        /*
  1144. X         * job options
  1145. X         */
  1146. X    case 'P':        /* -P printer */
  1147. X    case 'q':        /* -q queue (same thing) */
  1148. X        printer = arg;
  1149. X        return 1;
  1150. X    case 'S':        /* specify name of printer server */
  1151. X        lpd_server = arg;
  1152. X        return 1;
  1153. X    case '#':        /* num copies */
  1154. X        if (arg && isdigit (*arg)) {
  1155. X        num_copies = atoi (arg);
  1156. X        return 1;
  1157. X        }
  1158. X        break;
  1159. X    case 'C':        /* job class (default: local hostname) */
  1160. X        jobclass = arg;
  1161. X        return 1;
  1162. X    case 'J':        /* job title (default: first file name) */
  1163. X        jobtitle = arg;
  1164. X        return 1;
  1165. X    case 'i':        /* indent output (default: 8 chars) */
  1166. X        if (arg && isdigit (*arg)) {
  1167. X        indent = atoi (arg);
  1168. X        return 1;
  1169. X        }
  1170. X        else {
  1171. X        indent = 8;
  1172. X        return 0;
  1173. X        }
  1174. X    case '1':        /* troff font names */
  1175. X    case '2':
  1176. X    case '3':
  1177. X    case '4':
  1178. X        fontnames[opt[1]-'1']=arg;
  1179. X        return 1;
  1180. X    case 'w':        /* cols -- page width for pr */
  1181. X        if (arg && isdigit (*arg)) {
  1182. X        page_width = atoi (arg);
  1183. X        return 1;
  1184. X        }
  1185. X    case 'r':        /* remove file after spooling */
  1186. X        rflag = 1;
  1187. X        return 0;
  1188. X    case 'm':        /* send mail upon completion */
  1189. X        mflag = 1;
  1190. X        return 0;
  1191. X    case 'h':        /* don't print the burst page */
  1192. X        hflag = 1;
  1193. X        return 0;
  1194. X    case 's':        /* don't copy file -- symlink it */
  1195. X        fprintf (stderr,
  1196. X             "lpr: The -s (symlink) option is not supported\n");
  1197. X        fprintf (stderr,
  1198. X             "All files will be copied to the remote server\n");
  1199. X        return 0;
  1200. X    }
  1201. X    }
  1202. X    if (strcmp (opt, "-debug") == 0) {
  1203. X    debug = 1;
  1204. X    fprintf (stderr, "standalone lpr version %d.%d\n",
  1205. X         VERSION, PATCHLEVEL);
  1206. X    return 0;
  1207. X    }
  1208. X    fprintf (stderr, "lpr: warning: illegal option %s\n", opt);
  1209. X    return 0;
  1210. X}
  1211. X
  1212. int
  1213. option (opt, optarg)
  1214. char *opt; char *optarg;
  1215. X{
  1216. X    /*
  1217. X     * This hack is used to notice whether the argument for an option
  1218. X     * is appended to the option itself (e.g. "-Pprinter" rather than
  1219. X     * "-P" "printer".  If this is the case, and the option accepts an
  1220. X     * argument, split the arg into two args and call real_option().
  1221. X     * otherwise just pass our args to real_option().
  1222. X     */
  1223. X  
  1224. X    if (opt[2] && strchr ("SP#CJTi1234qw", opt[1])) {
  1225. X    char temp[3];
  1226. X    temp[0] = '-';
  1227. X    temp[1] = opt[1];
  1228. X    temp[2] = '\0';
  1229. X    real_option (temp, opt + 2);
  1230. X    return 0;
  1231. X    }
  1232. X    else
  1233. X    return real_option (opt, optarg);
  1234. X}
  1235. X
  1236. X/*
  1237. X * keep up with files to be deleted (for when using -r)
  1238. X * This is so we don't delete files until we *know* that the job
  1239. X * has been successfully submitted.
  1240. X */
  1241. X
  1242. struct delete_list {
  1243. X    char *name;
  1244. X    struct delete_list *next;
  1245. X} *head = NULL;
  1246. X
  1247. void
  1248. mark_for_delete (name)
  1249. char *name;
  1250. X{
  1251. X    struct delete_list *ptr = (struct delete_list *)
  1252. X    calloc (1, sizeof (struct delete_list));
  1253. X    if (!ptr) {
  1254. X    perror ("calloc");
  1255. X    return;
  1256. X    }
  1257. X    ptr->next = head;
  1258. X    ptr->name = name;
  1259. X    head = ptr;
  1260. X}
  1261. X
  1262. void
  1263. delete_marked_files ()
  1264. X{
  1265. X    struct delete_list *ptr;
  1266. X    for (ptr = head; ptr; ptr=ptr->next) {
  1267. X    if (ptr->name)
  1268. X        if (unlink (ptr->name) < 0) {
  1269. X        fprintf (stderr, "lpr: could not delete %s\n", ptr->name);
  1270. X        perror ("unlink");
  1271. X        }
  1272. X    }
  1273. X}
  1274. X
  1275. X/*
  1276. X * buffer management
  1277. X */
  1278. struct buffer {
  1279. X    char *ptr;            /* points to current append point */
  1280. X    int size;            /* how big is the buffer now? */
  1281. X    char text[1];        /* (extensible) array of bytes in the buffer */
  1282. X};
  1283. X
  1284. X/*
  1285. X * Create an empty buffer
  1286. X */
  1287. X
  1288. struct buffer *
  1289. create_buffer (initial_size)
  1290. unsigned int initial_size;
  1291. X{
  1292. X    struct buffer *buf;
  1293. X
  1294. X    if (initial_size <= 0)
  1295. X    initial_size = 1000;
  1296. X    if ((buf = (struct buffer *)
  1297. X     calloc (1, sizeof (struct buffer) + initial_size - 1)) == NULL)
  1298. X    return NULL;
  1299. X    buf->ptr = &(buf->text[0]);
  1300. X    buf->size = initial_size;
  1301. X    return buf;
  1302. X}
  1303. X
  1304. X/*
  1305. X * Ensure there is enough room in the buffer for "more" more bytes
  1306. X */
  1307. struct buffer *
  1308. enlarge_buffer (buf, more)
  1309. struct buffer *buf;
  1310. int more;
  1311. X{
  1312. X    int offset = buf->ptr - &(buf->text[0]);
  1313. X    int spaceleft = buf->size - offset;
  1314. X
  1315. X    if (more > spaceleft) {
  1316. X    int newsize = sizeof (struct buffer) + (buf->size * 2) - 1;
  1317. X    buf = (struct buffer *) realloc ((char *) buf, newsize);
  1318. X    if (buf == NULL) {
  1319. X        perror ("enlarge_buffer(): realloc failed");
  1320. X        return NULL;
  1321. X    }
  1322. X    buf->ptr = &(buf->text[0]) + offset;
  1323. X    buf->size = newsize;
  1324. X    }
  1325. X    return buf;
  1326. X}
  1327. X
  1328. X/*
  1329. X * Append up to max_size bytes from an open file to buffer
  1330. X */
  1331. X
  1332. struct buffer *
  1333. read_file_into_buffer (buf, fd, max_size)
  1334. struct buffer *buf;
  1335. int fd;
  1336. unsigned max_size;
  1337. X{
  1338. X    int real_size = 0;
  1339. X
  1340. X    while (max_size > 0)  {
  1341. X    int foo = min (max_size, max_net_read);
  1342. X    if ((buf = enlarge_buffer (buf, foo)) == NULL)
  1343. X        return NULL;
  1344. X    if ((foo = read (fd, buf->ptr, foo)) < 0)
  1345. X        return NULL;
  1346. X    if (foo == 0)
  1347. X        break;
  1348. X    buf->ptr += foo;
  1349. X    max_size -= foo;
  1350. X    real_size += foo;
  1351. X    }
  1352. X    return buf;
  1353. X}
  1354. X
  1355. X/*
  1356. X * Append a NUL-terminated string to the buffer
  1357. X */
  1358. X
  1359. struct buffer *
  1360. append_string_to_buffer (buf, string, length)
  1361. struct buffer *buf;
  1362. char *string;
  1363. int length;
  1364. X{
  1365. X    if ((buf = enlarge_buffer (buf, length)) == NULL) {
  1366. X    fprintf (stderr, "lpr: file too big to fit in memory\n");
  1367. X    exit (EXIT_FAIL);
  1368. X    }
  1369. X    strncpy (buf->ptr, string, length);
  1370. X    buf->ptr += length;
  1371. X    return buf;
  1372. X}
  1373. X
  1374. X/*
  1375. X * Write out the entire contents of buffer to the file fd.
  1376. X */
  1377. X
  1378. int
  1379. send_file_from_buffer (fd, buf)
  1380. int fd; struct buffer *buf;
  1381. X{
  1382. X    char *wptr = buf->text;
  1383. X    while (wptr < buf->ptr) {
  1384. X    unsigned int foo = min (buf->ptr - wptr, max_net_write);
  1385. X    if ((foo = y_write (fd, wptr, foo)) < 0)
  1386. X        return EOF;
  1387. X    wptr += foo;
  1388. X    }
  1389. X    return 0;
  1390. X}
  1391. X
  1392. X/*
  1393. X * free up a buffer
  1394. X */
  1395. X
  1396. void
  1397. free_buffer (buf)
  1398. struct buffer *buf;
  1399. X{
  1400. X    if (buf)
  1401. X    cfree (buf);
  1402. X}
  1403. X
  1404. int
  1405. buffer_size (buf)
  1406. struct buffer *buf;
  1407. X{
  1408. X    if (buf)
  1409. X    return (buf->ptr - buf->text);
  1410. X    return EOF;
  1411. X}
  1412. X
  1413. X/*
  1414. X * Look at a file buffer and guess what kind of file it is.  This is called
  1415. X * when we aren't given an explicit file type option.
  1416. X */
  1417. X
  1418. char
  1419. guess_file_type (buf, fname)
  1420. struct buffer *buf; char *fname;
  1421. X{
  1422. X    char *ptr = buf->text;
  1423. X    if (ptr[0] == '%' && ptr[1] == '!')
  1424. X    return 'f';        /* print PostScript as plain file */
  1425. X    if (ptr[0] == '\367' && ptr[1] == 2) {
  1426. X    fprintf (stderr, "lpr: %s is a TeX .dvi file, assuming -d\n", fname);
  1427. X    return 'd';        /* TeX .dvi file */
  1428. X    }
  1429. X    if (ptr[0] == '\100' && ptr[1] == '\357')  {
  1430. X    fprintf (stderr, "lpr: %s is a C/A/T troff output file, assuming -t\n",
  1431. X         fname);
  1432. X    return 't';        /* C/A/T troff file */
  1433. X    }
  1434. X    return 'f';            /* default file type is plain file */
  1435. X}
  1436. X
  1437. int
  1438. check_for_bogus_file (buf, type, filename)
  1439. struct buffer *buf; char type; char *filename;
  1440. X{
  1441. X    char *ptr = buf->text;
  1442. X
  1443. X    if (buf->ptr == buf->text) {
  1444. X    fprintf (stderr, "lpr: skipping zero-length file %s\n", filename);
  1445. X    return EOF;
  1446. X    }
  1447. X    
  1448. X    if (ptr[0] == '\037' && ptr[1] == '\235') {
  1449. X    fprintf (stderr, "lpr: %s is a compressed file -- ignoring it\n",
  1450. X         filename);
  1451. X    return EOF;
  1452. X    }
  1453. X    if (type == 'd') {
  1454. X    if (ptr[0] == '\367' && ptr[1] == '\002') {
  1455. X        /* sometimes .dvi files have trailing NULs when they
  1456. X           shouldn't have.  Remove these from the buffer and
  1457. X           check that the .dvi file ends with a \337 byte. */
  1458. X        if (buf->ptr[-1] == '\0') {
  1459. X        while (buf->ptr[-1] == '\0')
  1460. X            --(buf->ptr);
  1461. X        }
  1462. X        if (buf->ptr[-1] == '\337')
  1463. X        return 0;
  1464. X    }
  1465. X    fprintf (stderr, "lpr: %s is not a valid .dvi file", filename);
  1466. X    return EOF;
  1467. X    }
  1468. X    if (memcmp (ptr, "!<arch>\n", 8) == 0) {
  1469. X    fprintf (stderr, "lpr: %s is a UNIX library archive -- ignoring it",
  1470. X         filename);
  1471. X    return EOF;
  1472. X    }
  1473. X    return 0;
  1474. X}
  1475. X
  1476. X
  1477. X/*
  1478. X * Send a command to the remote server and wait for a response.  Return
  1479. X * the first byte of the response, or EOF on error.
  1480. X */
  1481. X
  1482. int
  1483. send_command (fd, buf, size)
  1484. int fd; char *buf; unsigned int size;
  1485. X{
  1486. X    char x[1];
  1487. X    if (x_write (fd, buf, size) != size)
  1488. X    return EOF;
  1489. X    if (x_read (fd, x, 1) != 1)
  1490. X    return EOF;
  1491. X    return *x;
  1492. X}
  1493. X
  1494. X
  1495. X/*
  1496. X * structure used to keep track of print jobs
  1497. X */
  1498. struct job {
  1499. X    int jobid;            /* integer job id 1-999 */
  1500. X    int fd;            /* fd of lpd socket */
  1501. X    int control_file_number;    /* current file number */
  1502. X    int data_file_number;    /* data_file_number */
  1503. X    struct buffer *cfile;    /* buffer to build control file */
  1504. X};
  1505. X
  1506. X/*
  1507. X * add a record to a control file
  1508. X */
  1509. void
  1510. control (job, cmd, arg)
  1511. struct job *job; char cmd; char *arg;
  1512. X{
  1513. X    char buf[512];
  1514. X    sprintf (buf, "%c%s\n", cmd, arg);
  1515. X    job->cfile = append_string_to_buffer (job->cfile, buf, strlen (buf));
  1516. X}
  1517. X
  1518. X
  1519. X/*
  1520. X * create a print job.  Return a job ptr on success or NULL on error.
  1521. X */
  1522. struct job *
  1523. open_job (queuename)
  1524. char *queuename;
  1525. X{
  1526. X    struct job *job;
  1527. X    char buf[512];
  1528. X    char x;
  1529. X
  1530. X    if ((job = (struct job *) calloc (1, sizeof (struct job))) == NULL)
  1531. X    return NULL;
  1532. X    /*
  1533. X     * generate a job #.  Really, this should be maintained on a
  1534. X     * per-(host,queue) basis, so we won't have naming conflicts.
  1535. X     * for now, we just generate something pseudo-random.
  1536. X     */
  1537. X    job->jobid = time (0) % 1000;
  1538. X    job->fd = open_lpd (lpd_server);
  1539. X    if (job->fd  < 0) {
  1540. X    free (job);
  1541. X    return NULL;
  1542. X    }
  1543. X
  1544. X    sprintf (buf, "\2%s\n", queuename);
  1545. X    if ((x = send_command (job->fd, buf, strlen (buf))) != 0) {
  1546. X    if (isprint (x)) {
  1547. X        int foo;
  1548. X        *buf = x;
  1549. X        foo = x_read (job->fd, buf+1, sizeof(buf)-1);
  1550. X        fprintf (stderr,
  1551. X             "lpr: server %s refused job with message:\n",
  1552. X             lpd_server);
  1553. X        fprintf (stderr, "%.*s", foo+1, buf);
  1554. X    }
  1555. X    else {
  1556. X        fprintf (stderr,
  1557. X             "lpr: server %s refused job for printer %s\n",
  1558. X             lpd_server, queuename);
  1559. X    }
  1560. X    close (job->fd);
  1561. X    free (job);
  1562. X    return NULL;
  1563. X    }
  1564. X
  1565. X    job->control_file_number = 0;
  1566. X    job->data_file_number = 0;
  1567. X    job->cfile = create_buffer (1000);
  1568. X
  1569. X    control (job, 'H', hostname);
  1570. X    control (job, 'P', username);
  1571. X    if (hflag == 0) {
  1572. X    control (job, 'J', jobtitle);
  1573. X    control (job, 'C', jobclass);
  1574. X    }
  1575. X    control (job, 'L', username);
  1576. X    if (title)
  1577. X    control (job, 'T', title);
  1578. X    if (mflag)
  1579. X    control (job, 'M', email_address);
  1580. X    return job;
  1581. X}
  1582. X
  1583. void
  1584. concoct_file_name (c, job, str)
  1585. char c; struct job *job; char *str;
  1586. X{
  1587. X    int x = c == 'd' ? job->data_file_number++ : job->control_file_number++;
  1588. X    sprintf (str, "%cf%c%03d%s", c,
  1589. X         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[x],
  1590. X         job->jobid, hostname);
  1591. X}
  1592. X
  1593. X/*
  1594. X * Send a file to be printed.  Return 1 on success and 0 on error.
  1595. X * (i.e. # of files sent). 
  1596. X * print diagnostic messages to stderr as necessary
  1597. X * If file == NULL, print standard input
  1598. X */
  1599. int
  1600. send_print_file (job, file, file_type)
  1601. struct job *job; char *file; char file_type;
  1602. X{
  1603. X    int estimated_size;        /* how big we think the file is */
  1604. X    int max_size;        /* max size to print */
  1605. X    int real_size;
  1606. X    int fd = EOF;        /* fd of file */
  1607. X    struct buffer *dfile = NULL; /* buffer to read file into */
  1608. X    char *reason = NULL;    /* reason file xfer failed */
  1609. X    char data_file_name[512];    /* name of temporary data file */
  1610. X    char buf[512];
  1611. X    int x;
  1612. X    int i;
  1613. X
  1614. X    /*
  1615. X     * open the file and find out how big it is
  1616. X     * estimated_size is used to determine how much space to allocate.
  1617. X     * max_size is used to decide how much to read in.  Under VMS
  1618. X     * we don't ever want to read too much, because we might get
  1619. X     * unwanted garbage at the end of a fixed-length record file.
  1620. X     */
  1621. X    if (file) {
  1622. X    struct stat sbuf;    
  1623. X    if (stat (file, &sbuf) < 0) {
  1624. X        perror (file);
  1625. X        return 0;
  1626. X    }
  1627. X    max_size = estimated_size = sbuf.st_size;
  1628. X    if ((fd = open (file, 0)) < 0) {
  1629. X        perror (file);
  1630. X        return 0;
  1631. X    }
  1632. X    }
  1633. X    else {
  1634. X    struct stat sbuf;
  1635. X    file = "standard input"; /* for page headers, error messages */
  1636. X    estimated_size = 64000;
  1637. X    max_size = 5*1024*1024;    /* 5 megabytes */
  1638. X    fd = 0;
  1639. X#ifdef unix
  1640. X    /*
  1641. X     * UNIX-specific performance optimization:
  1642. X     * If standard input is an ordinary file, get size estimate
  1643. X     * with fstat()
  1644. X     */
  1645. X    if (fstat (fd, &sbuf) < 0) {
  1646. X        if ((sbuf.st_mode & S_IFMT) == S_IFREG)
  1647. X        estimated_size = sbuf.st_size;
  1648. X    }
  1649. X#endif
  1650. X    }
  1651. X
  1652. X    /*
  1653. X     * create a buffer and read the file into it.
  1654. X     */
  1655. X    concoct_file_name ('d', job, data_file_name);
  1656. X    if ((dfile = create_buffer (estimated_size)) == NULL) {
  1657. X        reason = "file too big to fit in memory";
  1658. X    goto abort;
  1659. X    }
  1660. X    if ((dfile = read_file_into_buffer (dfile, fd, max_size)) == NULL) {
  1661. X    reason = "error reading file";
  1662. X    goto abort;
  1663. X    }
  1664. X
  1665. X    /*
  1666. X     * file transfer successful.  Add this file to the print job,
  1667. X     * clean up, and return.
  1668. X     */
  1669. X    if (file_type == '?')
  1670. X    file_type = guess_file_type (dfile, file);
  1671. X    /*
  1672. X     * check for bogus file formats.  Refuse to print anything that
  1673. X     * is obviously bogus.
  1674. X     */
  1675. X    if (check_for_bogus_file (dfile, file_type, file))
  1676. X    goto okay;
  1677. X
  1678. X    /*
  1679. X     * transfer the file to the server, with error checking
  1680. X     */
  1681. X    sprintf (buf, "\3%d %s\n", buffer_size(dfile), data_file_name);
  1682. X    if ((x = send_command (job->fd, buf, strlen (buf))) != 0) {
  1683. X    switch (x) {
  1684. X    case 1:
  1685. X        break;
  1686. X    case 2:
  1687. X        reason = "not enough disk space on server (or file is too large)";
  1688. X        break;
  1689. X    case EOF:
  1690. X        reason = "connection to printer server broken";
  1691. X        break;
  1692. X    default:
  1693. X        if (isprint (x)) {
  1694. X        *buf = x;
  1695. X        x = x_read (job->fd, buf + 1, sizeof (buf) - 1);
  1696. X        buf[x+1] = '\0';
  1697. X        reason = buf;
  1698. X        }
  1699. X    }
  1700. X    goto abort;
  1701. X    }
  1702. X    if (send_file_from_buffer (job->fd, dfile) != 0)
  1703. X    goto abort;
  1704. X    if (send_command (job->fd, "", 1) < 0)
  1705. X    goto abort;
  1706. X
  1707. X    if (file_type == 'p' && !title)
  1708. X    control (job, 'P', file);
  1709. X    for (i = 0; i < num_copies; ++i)
  1710. X    control (job, file_type, data_file_name);
  1711. X    control (job, 'U', data_file_name);
  1712. X    control (job, 'N', file);
  1713. X okay:
  1714. X    free_buffer (dfile);
  1715. X    close (fd);
  1716. X    return 1;
  1717. X
  1718. X
  1719. X    /*
  1720. X     * file transfer failed.  print error message and clean up
  1721. X     */
  1722. X abort:
  1723. X    fprintf (stderr, "lpr: unable to send file %s to print server %s\n",
  1724. X         file, lpd_server);
  1725. X    if (reason)
  1726. X    fprintf (stderr, "reason: %s\n", reason);
  1727. X    if (dfile)
  1728. X    free_buffer (dfile);
  1729. X    if (fd > 0)
  1730. X    close (fd);
  1731. X    return 0;
  1732. X}
  1733. X
  1734. X/*
  1735. X * send the control file.  Return 0 on success, nonzero on error.
  1736. X */
  1737. send_control_file (job)
  1738. struct job *job;
  1739. X{
  1740. X    char buf[512];
  1741. X    char control_file_name[512];
  1742. X
  1743. X    concoct_file_name ('c', job, control_file_name);
  1744. X    sprintf (buf, "\2%d %s\n", job->cfile->ptr - job->cfile->text,
  1745. X         control_file_name);
  1746. X    if (send_command (job->fd, buf, strlen (buf)) < 0)
  1747. X    return 1;
  1748. X    if (send_file_from_buffer (job->fd, job->cfile) != 0)
  1749. X    return 1;
  1750. X    if (send_command (job->fd, "", 1) < 0)
  1751. X    return 1;
  1752. X    return 0;
  1753. X}
  1754. X
  1755. X/*
  1756. X * close a job normally and delete its resources
  1757. X */
  1758. int
  1759. close_job (job)
  1760. struct job *job;
  1761. X{
  1762. X    int x;
  1763. X    if (job == NULL)
  1764. X    return EOF;
  1765. X    x = send_control_file (job);
  1766. X    if (job->cfile)
  1767. X    free_buffer (job->cfile);
  1768. X    close (job->fd);
  1769. X    cfree (job);
  1770. X    return x;
  1771. X}
  1772. X
  1773. X/*
  1774. X * abort a job and delete its resources
  1775. X */
  1776. void
  1777. abort_job (job)
  1778. struct job *job;
  1779. X{
  1780. X    if (job == NULL)
  1781. X    return;
  1782. X    x_write (job->fd, "\1\n", 2);
  1783. X    close (job->fd);
  1784. X    if (job->cfile)
  1785. X    free_buffer (job->cfile);
  1786. X    cfree (job);
  1787. X}
  1788. X
  1789. X
  1790. char *
  1791. get_lpd_server ()
  1792. X{
  1793. X    FILE *fp;
  1794. X    static char *buf[512];
  1795. X    
  1796. X    if ((fp = fopen ("/etc/LPD_SERVER", "r")) == (FILE *) NULL)
  1797. X    return NULL;
  1798. X    if (fscanf (fp, " %511s", buf) != 1)
  1799. X    return NULL;
  1800. X    return (char *) buf;
  1801. X}
  1802. X
  1803. X
  1804. X/*
  1805. X * Dummy main program exists to find out what name we are being called
  1806. X * by (under UNIX, anyway) and act appropriately.  This program has
  1807. X * multiple personalities...
  1808. X */
  1809. X
  1810. main (argc, argv)
  1811. int argc; char **argv;
  1812. X{
  1813. X#ifdef unix
  1814. X    char *progname = NULL;
  1815. X    char *strrchr ();
  1816. X#endif
  1817. X    char *p;
  1818. X
  1819. X    /*
  1820. X     * inherit some defaults from the environment
  1821. X     */
  1822. X
  1823. X    printer = getenv ("PRINTER");
  1824. X    if (printer == NULL)
  1825. X    printer = "lp";
  1826. X    lpd_server = getenv ("LPD_SERVER");
  1827. X    if (lpd_server == NULL)
  1828. X    lpd_server = get_lpd_server ();
  1829. X
  1830. X    sysdep ();
  1831. X
  1832. X#ifdef unix
  1833. X    /*
  1834. X     * look at the last component of the name we were invoked with
  1835. X     * and determine how to behave.
  1836. X     */
  1837. X    progname = strrchr (argv[0], '/');
  1838. X    if (progname == NULL)
  1839. X    progname = argv[0];
  1840. X    else
  1841. X    progname++;
  1842. X
  1843. X    if (strcmp (progname, "lpq") == 0)
  1844. X    return (lpq (argc, argv));
  1845. X    else if (strcmp (progname, "lprm") == 0)
  1846. X    return (lprm (argc, argv));
  1847. X#endif
  1848. X
  1849. X    /*
  1850. X     * if first argument is -remove or -delete, behave as lprm
  1851. X     * if first argumetn is -showqueue, behave as lpq
  1852. X     */
  1853. X
  1854. X    if (argc > 1) {
  1855. X    if (strcmp (argv[1], "-remove") == 0)
  1856. X        return (lprm (argc-1, argv+1));
  1857. X    else if (strcmp (argv[1], "-delete") == 0)
  1858. X        return (lprm (argc-1, argv+1));
  1859. X    else if (strcmp (argv[1], "-showqueue") == 0)
  1860. X        return (lpq (argc-1, argv+1));
  1861. X    }
  1862. X
  1863. X    return (lpr (argc, argv));
  1864. X}
  1865. X
  1866. X/*
  1867. X * queue one or more files for printing
  1868. X */
  1869. X
  1870. lpr (argc, argv)
  1871. int argc; char **argv;
  1872. X{
  1873. X    struct job *job = NULL;
  1874. X    int i;
  1875. X    int file_args = 0;
  1876. X    int files_printed = 0;
  1877. X
  1878. X    jobclass = hostname;
  1879. X    jobtitle = NULL;
  1880. X
  1881. X    for (i = 1; i < argc; ++i) {
  1882. X    if (*argv[i] == '-')
  1883. X        i += option (argv[i], argv[i+1]);
  1884. X    else {
  1885. X        if (!jobtitle) {
  1886. X        char *ptr = strrchr (argv[i], '/');
  1887. X        jobtitle = ptr ? ptr + 1 : argv[i];
  1888. X        }
  1889. X        if (job == NULL && (job = open_job (printer)) == NULL)
  1890. X        exit (EXIT_FAIL);
  1891. X        file_args++;
  1892. X        if (send_print_file (job, argv[i], file_type)) {
  1893. X        files_printed++;
  1894. X        if (rflag)
  1895. X            mark_for_delete (argv[i]);
  1896. X        }
  1897. X    }
  1898. X    }
  1899. X    if (file_args == 0) {
  1900. X    if (!jobtitle)
  1901. X        jobtitle = "stdin";
  1902. X    if ((job = open_job (printer)) == NULL)
  1903. X        exit (EXIT_FAIL);
  1904. X    files_printed += send_print_file (job, 0, file_type);
  1905. X    }
  1906. X    if (files_printed > 0) {
  1907. X    if (close_job (job)) {
  1908. X        delete_marked_files ();
  1909. X        exit (EXIT_OK);
  1910. X    }
  1911. X    else
  1912. X        exit (EXIT_FAIL);
  1913. X    }
  1914. X    else
  1915. X    exit (EXIT_FAIL);
  1916. X    exit (EXIT_OK);
  1917. X}
  1918. X
  1919. X/*
  1920. X * print contents of printer queue
  1921. X * "lpq -l" prints in long format
  1922. X */
  1923. X
  1924. lpq (argc, argv)
  1925. int argc; char **argv;
  1926. X{
  1927. X    int i;
  1928. X    char buf[512];
  1929. X    int fd;
  1930. X    int x;
  1931. X
  1932. X    for (i = 1; i < argc ; ++i) {
  1933. X    if (*argv[i] == '-')
  1934. X        i += option (argv[i], argv[i+1]);
  1935. X    else
  1936. X        break;
  1937. X    }
  1938. X
  1939. X    if ((fd = open_lpd (lpd_server)) < 0)
  1940. X    exit (EXIT_FAIL);
  1941. X
  1942. X    if (lflag)
  1943. X    sprintf (buf, "\004%s", printer);
  1944. X    else
  1945. X    sprintf (buf, "\003%s", printer);
  1946. X
  1947. X    for (; i < argc; ++i) {
  1948. X    strcat (buf, " ");
  1949. X    strcat (buf, argv[i]);
  1950. X    }
  1951. X
  1952. X    strcat (buf, "\n");
  1953. X    if (x_write (fd, buf, strlen (buf)) != 0) {
  1954. X    while ((x = x_read (fd, buf, sizeof buf)) > 0)
  1955. X        fwrite (buf, sizeof (char), x, stdout);
  1956. X    }
  1957. X    close (fd);
  1958. X    return 0;
  1959. X}
  1960. X
  1961. X/*
  1962. X * remove jobs from queue
  1963. X */
  1964. X
  1965. lprm (argc, argv)
  1966. int argc; char **argv;
  1967. X{
  1968. X    int fd;
  1969. X    int i;
  1970. X    char buf[512];
  1971. X    int x;
  1972. X    int response_length = 0;
  1973. X    int remove_all = 0;
  1974. X
  1975. X    for (i = 1; i < argc; ++i) {
  1976. X    if (strcmp (argv[i], "-") == 0)
  1977. X        remove_all++;
  1978. X    else if (*argv[i] == '-')
  1979. X        i += option (argv[i], argv[i+1]);
  1980. X    else
  1981. X        break;
  1982. X    }
  1983. X
  1984. X    if ((fd = open_lpd (lpd_server)) < 0)
  1985. X    exit (EXIT_FAIL);
  1986. X
  1987. X    /*
  1988. X     * If user asks to remove all queued files with "lprm -",
  1989. X     * need to check to see if user is privileged to do so.
  1990. X     * Allow root to remove all queued files, but any other
  1991. X     * user will just remove his/her own queued files.
  1992. X     * (remote server will only delete files queued by this system)
  1993. X     *
  1994. X     * "-all" is a magic user name which means delete all
  1995. X     * entries from this system.
  1996. X     */
  1997. X    if (remove_all) {
  1998. X#ifdef unix
  1999. X    if (strcmp (username, "root") == 0)
  2000. X        sprintf (buf, "\005%s %s", printer, "-all");
  2001. X    else
  2002. X        sprintf (buf, "\005%s %s %s", printer, username, username);
  2003. X#else
  2004. X    sprintf (buf, "\005%s %s %s", printer, username, username);
  2005. X#endif
  2006. X    }
  2007. X    else {
  2008. X    sprintf (buf, "\005%s %s", printer, username);
  2009. X    }
  2010. X
  2011. X    for (; i < argc; ++i) {
  2012. X    strcat (buf, " ");
  2013. X    strcat (buf, argv[i]);
  2014. X    }
  2015. X    strcat (buf, "\n");
  2016. X    if (x_write (fd, buf, strlen (buf)) != 0) {
  2017. X    while ((x = x_read (fd, buf, sizeof buf)) > 0) {
  2018. X        fwrite (buf, sizeof (char), x, stdout);
  2019. X        response_length += x;
  2020. X    }
  2021. X    }
  2022. X    close (fd);
  2023. X
  2024. X    /* If response_length is zero, assume the remove command failed.
  2025. X       Otherwise we should have received some confirmation message */
  2026. X
  2027. X    if (response_length == 0)
  2028. X    return 1;
  2029. X    return 0;
  2030. X}
  2031. END_OF_FILE
  2032. if test 25058 -ne `wc -c <'lpr.c'`; then
  2033.     echo shar: \"'lpr.c'\" unpacked with wrong size!
  2034. fi
  2035. # end of 'lpr.c'
  2036. fi
  2037. if test -f 'config.h' -a "${1}" != "-c" ; then 
  2038.   echo shar: Will not clobber existing file \"'config.h'\"
  2039. else
  2040. echo shar: Extracting \"'config.h'\" \(1220 characters\)
  2041. sed "s/^X//" >'config.h' <<'END_OF_FILE'
  2042. X/*
  2043. X * The printer server can be told to send email on job completion.
  2044. X * By default, this is sent to user@domain, where domain is the
  2045. X * fully-qualified Internet domain name (as returned by gethostbyname()).
  2046. X * If this will not work (perhaps because the host that is running this
  2047. X * version of lpr cannot receive mail), define MAKE_EMAIL_ADDRESS here
  2048. X * as a macro that will concoct an appropriate address.  Examples follow:
  2049. X *
  2050. X *
  2051. X * for a VMS machine that can receive DECnet mail, and a UNIX lpd server
  2052. X * that understands mail sent to user@node.DECnet, do:
  2053. X *
  2054. X * #define MAKE_EMAIL_ADDRESS(buf,user,dom) \
  2055. X       sprintf (buf, "%s@%s.DECnet", user, getenv ("SYS$NODE"))
  2056. X *
  2057. X *
  2058. X * for a VMS machine that can receive DECnet mail, and an lpd server
  2059. X * that can send mail to node::user, use:
  2060. X *
  2061. X * #define MAKE_EMAIL_ADDRESS(buf,user,dom) \
  2062. X *     sprintf (buf, "%s::%s", getenv ("SYS$NODE"), user)
  2063. X *
  2064. X * Or you can concoct your own.  For instance, we at UTK have an Internet
  2065. X * domain dnet.utk.edu that maps node.dnet.utk.edu to the appropriate
  2066. X * DECnet node for the purposes of email.  So we use:
  2067. X *
  2068. X * #define MAKE_EMAIL_ADDRESS(buf,user,dom) \
  2069. X *     sprintf (buf, "%s@%s.dnet.utk.edu", user, getenv ("SYS$NODE"))
  2070. X */
  2071. END_OF_FILE
  2072. if test 1220 -ne `wc -c <'config.h'`; then
  2073.     echo shar: \"'config.h'\" unpacked with wrong size!
  2074. fi
  2075. # end of 'config.h'
  2076. fi
  2077. if test -f 'common.h' -a "${1}" != "-c" ; then 
  2078.   echo shar: Will not clobber existing file \"'common.h'\"
  2079. else
  2080. echo shar: Extracting \"'common.h'\" \(498 characters\)
  2081. sed "s/^X//" >'common.h' <<'END_OF_FILE'
  2082. X#ifdef MAIN_PROGRAM
  2083. X#define STORAGE_CLASS
  2084. X#else
  2085. X#define STORAGE_CLASS extern
  2086. X#endif
  2087. X
  2088. STORAGE_CLASS char hostname[512];    /* name of this host */
  2089. STORAGE_CLASS char username[100];    /* name of user submitting job */
  2090. STORAGE_CLASS char email_address[512];    /* submitting user's email address */
  2091. STORAGE_CLASS int debug;        /* true if we want debugging output */
  2092. STORAGE_CLASS int max_net_read;        /* max # of bytes to read at a time */
  2093. STORAGE_CLASS int max_net_write;    /* max # of bytes to write at a time */
  2094. END_OF_FILE
  2095. if test 498 -ne `wc -c <'common.h'`; then
  2096.     echo shar: \"'common.h'\" unpacked with wrong size!
  2097. fi
  2098. # end of 'common.h'
  2099. fi
  2100. if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  2101.   echo shar: Will not clobber existing file \"'patchlevel.h'\"
  2102. else
  2103. echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
  2104. sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
  2105. X#define PATCHLEVEL 4
  2106. END_OF_FILE
  2107. if test 21 -ne `wc -c <'patchlevel.h'`; then
  2108.     echo shar: \"'patchlevel.h'\" unpacked with wrong size!
  2109. fi
  2110. # end of 'patchlevel.h'
  2111. fi
  2112. if test -f 'unix-tcp.c' -a "${1}" != "-c" ; then 
  2113.   echo shar: Will not clobber existing file \"'unix-tcp.c'\"
  2114. else
  2115. echo shar: Extracting \"'unix-tcp.c'\" \(4522 characters\)
  2116. sed "s/^X//" >'unix-tcp.c' <<'END_OF_FILE'
  2117. X/*
  2118. X * lpr interface for UNIX (i.e. BSD-ish) tcp
  2119. X */
  2120. X
  2121. X#include "common.h"
  2122. X#include "config.h"
  2123. X#include <stdio.h>
  2124. X#include <ctype.h>
  2125. X#include <sys/types.h>
  2126. X#include <sys/stat.h>
  2127. X#include <pwd.h>
  2128. X#include <netdb.h>
  2129. X#include <sys/socket.h>
  2130. X#include <errno.h>
  2131. X#include <netinet/in.h>
  2132. X
  2133. X#ifndef MAKE_EMAIL_ADDRESS
  2134. X#define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
  2135. X#endif
  2136. X
  2137. X
  2138. struct hostent *
  2139. gethostbynameoraddr (hostname)
  2140. char *hostname;
  2141. X{
  2142. X    if (isdigit (*hostname)) {
  2143. X    static struct hostent x;
  2144. X    static char *alias_list[1];
  2145. X    static unsigned long *addr_list[2];
  2146. X    static unsigned long ip_address;
  2147. X
  2148. X    ip_address = inet_addr (hostname);
  2149. X
  2150. X    addr_list[0] = &ip_address;
  2151. X    addr_list[1] = NULL;
  2152. X    alias_list[0] = NULL;
  2153. X
  2154. X    x.h_name = hostname;
  2155. X    x.h_aliases = alias_list;
  2156. X    x.h_addrtype = AF_INET;
  2157. X    x.h_length = sizeof (unsigned long);
  2158. X    x.h_addr_list = (char **) addr_list;
  2159. X    return &x;
  2160. X    }
  2161. X    return gethostbyname (hostname);
  2162. X}
  2163. X
  2164. void sysdep()
  2165. X{
  2166. X    struct passwd *pwd;
  2167. X    char *p;
  2168. X    struct hostent *hp;
  2169. X    char *getenv ();
  2170. X
  2171. X    gethostname (hostname, sizeof hostname);
  2172. X
  2173. X    if (pwd = getpwuid (getuid ()))
  2174. X    strcpy (username, pwd->pw_name);
  2175. X    else {
  2176. X    fprintf (stderr, "lpr: system problem: can't get your username!\n");
  2177. X    exit (1);
  2178. X    }
  2179. X    endpwent ();
  2180. X
  2181. X    hp = gethostbyname (hostname);
  2182. X    MAKE_EMAIL_ADDRESS(email_address, username, hp ? hp->h_name : hostname);
  2183. X}
  2184. X
  2185. X
  2186. X/*
  2187. X * Allocate a socket and bind it to a local privileged port
  2188. X * We have to be running set-uid to root to do this.
  2189. X */
  2190. X
  2191. int
  2192. get_priv_tcp_socket ()
  2193. X{
  2194. X    int fd;
  2195. X    int port;
  2196. X    struct sockaddr_in s;
  2197. X
  2198. X    if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) {
  2199. X    perror ("socket");
  2200. X    return EOF;
  2201. X    }
  2202. X    for (port = IPPORT_RESERVED-1; port > IPPORT_RESERVED / 2; port--) {
  2203. X    extern int errno;
  2204. X    s.sin_family = AF_INET;
  2205. X    s.sin_addr.s_addr = INADDR_ANY;
  2206. X    s.sin_port = htons (port);
  2207. X    if (bind (fd, (struct sockaddr *) &s, sizeof (s)) == 0)
  2208. X        return fd;
  2209. X    if (errno == EACCES) {
  2210. X        fprintf (stderr, "lpr warning: bind: cannot bind to privileged port\n");
  2211. X        return fd;
  2212. X    }
  2213. X    }
  2214. X    close (fd);
  2215. X    return EOF;
  2216. X}
  2217. X
  2218. X/*
  2219. X * Open a TCP connection to an lpd-server.
  2220. X * This requires that this program be run set-uid to root in order to be able
  2221. X * to bind a socket to a privileged port.
  2222. X */
  2223. X
  2224. int
  2225. open_lpd (server)
  2226. char *server;
  2227. X{
  2228. X    int fd;
  2229. X    int i;
  2230. X    int last_connect_failed;
  2231. X    struct hostent *hp;
  2232. X    struct servent *sp;
  2233. X    struct sockaddr_in s;
  2234. X
  2235. X    if (server == NULL || *server == '\0') {
  2236. X    fprintf (stderr, "lpr: no server host was specified.\n");
  2237. X    fprintf (stderr, "     Supply one with the -S option, or\n");
  2238. X    fprintf (stderr, "     by setting the LPD_SERVER environment variable\n");
  2239. X    return EOF;
  2240. X    }
  2241. X    if ((hp = gethostbynameoraddr (server)) == NULL) {
  2242. X    fprintf (stderr, "lpr: can't find network address for %s\n",
  2243. X         server);
  2244. X    fflush (stderr);
  2245. X    return EOF;
  2246. X    }
  2247. X
  2248. X    s.sin_family = AF_INET;
  2249. X    if ((sp = getservbyname ("printer", "tcp")) == NULL)
  2250. X    s.sin_port = htons (515);
  2251. X    else
  2252. X    s.sin_port = sp->s_port;
  2253. X
  2254. X    /*
  2255. X     * On some systems h_addr is a macro that is defined to be h_addr_list[0]
  2256. X     * On other (ancient) systems, h_addr is a member of the hostent structure.
  2257. X     * So if h_addr is defined as a macro, then we must have the list...
  2258. X     */
  2259. X
  2260. X#ifdef h_addr
  2261. X    for (i = 0; hp->h_addr_list[i] ; ++i) {
  2262. X    fd = get_priv_tcp_socket ();
  2263. X    disable_special_privileges ();
  2264. X    if (fd < 0)
  2265. X        return EOF;
  2266. X    bcopy (hp->h_addr_list[i], &s.sin_addr, sizeof (s.sin_addr));
  2267. X    if (debug)
  2268. X        fprintf (stderr, "Trying %s...", inet_ntoa (s.sin_addr));
  2269. X    last_connect_failed = 0; /* "I'm ashamed of this." - SMK */
  2270. X    if (connect (fd, &s, sizeof s) == 0) {
  2271. X        if (debug)
  2272. X        fprintf (stderr, "open\n");
  2273. X        break;
  2274. X    }
  2275. X    else {
  2276. X        close (fd);        /* reuse fd */
  2277. X        if (debug)
  2278. X        perror ("");
  2279. X        last_connect_failed = 1;
  2280. X    }
  2281. X    }
  2282. X    if (last_connect_failed) {
  2283. X    perror ("connect");
  2284. X    return EOF;
  2285. X    }
  2286. X#else
  2287. X    fd = get_priv_tcp_socket ();
  2288. X    disable_special_privileges ();
  2289. X    if (fd < 0)
  2290. X    return EOF;
  2291. X    bcopy (hp->h_addr, (char *) &s.sin_addr, sizeof(s.sin_addr));
  2292. X    if (connect (fd, &s, sizeof s) < 0) {
  2293. X    perror ("connect");
  2294. X    close (fd);
  2295. X    return EOF;
  2296. X    }
  2297. X#endif
  2298. X
  2299. X    max_net_read = max_net_write = 32767;
  2300. X    return fd;
  2301. X}
  2302. X
  2303. X/*
  2304. X * Turn off set-uid privileges.
  2305. X * We have to be running set-uid to root in order to bind to a privileged
  2306. X * port.  In order to minimize the security risk, this function is called
  2307. X * from open_job() immediately after open_lpd() returns.
  2308. X */
  2309. X
  2310. disable_special_privileges ()
  2311. X{
  2312. X    setuid (getuid ());
  2313. X}
  2314. END_OF_FILE
  2315. if test 4522 -ne `wc -c <'unix-tcp.c'`; then
  2316.     echo shar: \"'unix-tcp.c'\" unpacked with wrong size!
  2317. fi
  2318. # end of 'unix-tcp.c'
  2319. fi
  2320. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  2321.   echo shar: Will not clobber existing file \"'Makefile'\"
  2322. else
  2323. echo shar: Extracting \"'Makefile'\" \(3332 characters\)
  2324. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  2325. X# fix SysV brain-damage
  2326. SHELL=/bin/sh
  2327. X#
  2328. DEFAULT_SERVER=
  2329. X#
  2330. X# pick a back-end driver from one of the following:
  2331. X#
  2332. DRIVER=unix-tcp.o        # UNIX w/BSD-style sockets
  2333. X# (others to follow...maybe)
  2334. X#
  2335. X# This program was originally developed with GCC, but it doesn't always
  2336. X# use the same calling sequence as the system libraries (particularly
  2337. X# inet_ntoa()), so I don't use it for this anymore.
  2338. X# If your C compiler runs on UNIX, but doesn't define "unix" as a macro,
  2339. X# define it on the CFLAGS line with -Dunix
  2340. X# Don't get nervous, I always compile with -g.
  2341. X#
  2342. X#CC=gcc -ansi -g -Dunix
  2343. CFLAGS=-g -Dunix
  2344. X#
  2345. X# nroff (or some facsimile thereof) is used to format the man pages.
  2346. X# I used groff because that way I don't end up with man pages that say
  2347. X# "SunOS" or "Ultrix" or some such.
  2348. X#
  2349. X#NROFF=nroff
  2350. NROFF=groff -Tascii
  2351. X#
  2352. X# Set BINDIR to the directory where the program will be installed.
  2353. X# This doesn't affect the compilation, so you can set this after
  2354. X# compiling.
  2355. X#
  2356. BINDIR=/usr/local/bin
  2357. X#
  2358. X# Set GWDIR to where the (optional) dnet-to-tcp lpr gateway will
  2359. X# be installed.  This doesn't affect compilation either.
  2360. X#
  2361. GWDIR=/usr/sunlink/dni
  2362. X#
  2363. X# List of sources, for bundling together in a package
  2364. X#
  2365. SRCS=lpr.c config.h common.h patchlevel.h \
  2366. X    unix-tcp.c Makefile \
  2367. X    vms-ucx-tcp.c vms-decnet.c vms-win-tcp.c descrip.mms \
  2368. X    dnet-lpd-gw.c \
  2369. X    lpr.man lpr.cat
  2370. X#
  2371. X# other stuff that goes with the package
  2372. X#
  2373. PKG=BLURB README MANIFEST LICENSE ChangeLog $(SRCS)
  2374. X
  2375. X#
  2376. X# The -lsocket stuff is an attempt to get this to work on machines
  2377. X# that have a BSD socket library built on top of STREAMS-based tcp
  2378. X# without having to have a hairy configuration program just to compile
  2379. X# this.
  2380. X#
  2381. lpr: lpr.c config.h $(DRIVER)
  2382. X    -if [ -f /usr/lib/libsocket.a ] ; then \
  2383. X        $(CC) $(CFLAGS) -o lpr lpr.c $(DRIVER) -lsocket ; \
  2384. X    else \
  2385. X        $(CC) $(CFLAGS) -o lpr lpr.c $(DRIVER) ; \
  2386. X    fi
  2387. X
  2388. dnet-lpd-gw: dnet-lpd-gw.c unix-tcp.o
  2389. X    $(CC) $(CFLAGS)  -o dnet-lpd-gw dnet-lpd-gw.c unix-tcp.o
  2390. X
  2391. X#
  2392. X# preformatted man page, in case someone doesn't have nroff
  2393. X#
  2394. lpr.cat: lpr.man
  2395. X    $(NROFF) -man lpr.man > lpr.cat
  2396. X
  2397. X#
  2398. X# The wierd "rm || mv" stuff is an attempt to work around SysV brain
  2399. X# damage that won't let you rm a program that is running.
  2400. X#
  2401. install: lpr
  2402. X    cp lpr $(BINDIR)/lpr.new
  2403. X    chown root $(BINDIR)/lpr.new
  2404. X    chmod 4711 $(BINDIR)/lpr.new
  2405. X    -rm  $(BINDIR)/lpr || mv $(BINDIR)/lpr $(BINDIR)/lpr.old
  2406. X    mv $(BINDIR)/lpr.new $(BINDIR)/lpr
  2407. X    -rm $(BINDIR)/lprm || mv $(BINDIR)/lprm $(BINDIR)/lprm.old
  2408. X    ln $(BINDIR)/lpr $(BINDIR)/lprm
  2409. X    -rm $(BINDIR)/lpq || mv $(BINDIR)/lpq $(BINDIR)/lpq.old
  2410. X    ln $(BINDIR)/lpr $(BINDIR)/lpq
  2411. X
  2412. install-gw: dnet-lpd-gw
  2413. X    rm -f $(GWDIR)/dnet-lpd-gw
  2414. X    cp dnet-lpd-gw $(GWDIR)
  2415. X    chown root $(GWDIR)/dnet-lpd-gw
  2416. X    chmod 4711 $(GWDIR)/dnet-lpd-gw
  2417. X
  2418. clean:
  2419. X    rm -f lpr dnet-lpd-gw *.o
  2420. X
  2421. X#
  2422. X# various packaging routines.
  2423. X#
  2424. port-lpr.vms: $(PKG)
  2425. X    /bin/true > port-lpr.vms
  2426. X    for i in $(PKG) ; do \
  2427. X        echo '$$ write sys$$output "creating' $$i'"' ; \
  2428. X        echo '$$ CREATE' $$i ; \
  2429. X        cat $$i ; \
  2430. X    done >> port-lpr.vms
  2431. X    echo '$$ exit' >> port-lpr.vms
  2432. X
  2433. port-lpr.tar: $(PKG)
  2434. X    tar cf port-lpr.tar $(PKG)
  2435. X
  2436. port-lpr.tar.Z.uu: $(PKG)
  2437. X    tar cf - $(PKG) | compress | uuencode port-lpr.tar.Z > port-lpr.tar.Z.uu
  2438. X
  2439. port-lpr.uushar: $(PKG)
  2440. X    for i in $(PKG) ; do uuencode $$i < $$i ; done > port-lpr.uushar
  2441. X
  2442. port-lpr.shar: $(PKG)
  2443. X    shar $(PKG) > port-lpr.shar
  2444. X
  2445. print:
  2446. X    enscript -2r `ls $(SRCS) | grep '.*\.[ch]'`
  2447. END_OF_FILE
  2448. if test 3332 -ne `wc -c <'Makefile'`; then
  2449.     echo shar: \"'Makefile'\" unpacked with wrong size!
  2450. fi
  2451. # end of 'Makefile'
  2452. fi
  2453. if test -f 'vms-ucx-tcp.c' -a "${1}" != "-c" ; then 
  2454.   echo shar: Will not clobber existing file \"'vms-ucx-tcp.c'\"
  2455. else
  2456. echo shar: Extracting \"'vms-ucx-tcp.c'\" \(8256 characters\)
  2457. sed "s/^X//" >'vms-ucx-tcp.c' <<'END_OF_FILE'
  2458. X/*
  2459. X * lpr interface for VAX/VMS UCX TCP
  2460. X */
  2461. X
  2462. X#include "common.h"
  2463. X#include "config.h"
  2464. X#include <stdio.h>
  2465. X#include <ctype.h>
  2466. X#include <types.h>
  2467. X#include <stat.h>
  2468. X#include <netdb.h>
  2469. X#include <socket.h>
  2470. X#include <errno.h>
  2471. X#include <in.h>
  2472. X#include <prvdef.h>
  2473. X#include <jpidef.h>
  2474. X#include <ssdef.h>
  2475. X#include <lnmdef.h>
  2476. X
  2477. struct item_list {
  2478. X    unsigned short buffer_length;
  2479. X    unsigned short item_code;
  2480. X    char *buffer_address;
  2481. X    char *length_address;
  2482. X};
  2483. X
  2484. struct descrip {
  2485. X    int length;
  2486. X    char *ptr;
  2487. X};
  2488. X
  2489. X/*
  2490. X * Translate a VAX/VMS logical name, given the name we want to translate
  2491. X * and the table name we want to search with.
  2492. X */
  2493. X
  2494. int
  2495. translate_logical_name (table, name, buf, size)
  2496. char *table; char *name; char *buf; int size;
  2497. X{
  2498. X    struct descrip table_d;
  2499. X    struct descrip name_d;
  2500. X    struct item_list item_list[2];
  2501. X    int foo;
  2502. X    int status;
  2503. X
  2504. X    table_d.length = strlen (table);
  2505. X    table_d.ptr = table;
  2506. X    name_d.length = strlen (name);
  2507. X    name_d.ptr = name;
  2508. X    item_list[0].buffer_length = size - 1;
  2509. X    item_list[0].item_code = LNM$_STRING;
  2510. X    item_list[0].buffer_address = buf;
  2511. X    item_list[0].length_address = &foo;
  2512. X    item_list[1].buffer_length = 0;
  2513. X    item_list[1].item_code = 0;
  2514. X    item_list[1].buffer_address = 0;
  2515. X    item_list[1].length_address = 0;
  2516. X    status = SYS$TRNLNM (0, &table_d, &name_d, 0, item_list);
  2517. X    if ((status & 01) != 01)
  2518. X    lib$signal (status);
  2519. X    if (foo >= 0 && foo < size)
  2520. X    buf[foo] = '\0';
  2521. X    return ((status & 01) ? 0 : EOF);
  2522. X}
  2523. X
  2524. X/*
  2525. X * Determine the DECnet node name by translating the system logical name
  2526. X * SYS$NODE.  We use this function rather than the getenv() function,
  2527. X * just to make sure the user doesn't define his/her own SYS$NODE variable
  2528. X * and pretend he/she is submitting the print job from somewhere else.
  2529. X */
  2530. X
  2531. int
  2532. get_decnet_node_name (buf, size)
  2533. char *buf; int size;
  2534. X{
  2535. X    
  2536. X    if (!translate_logical_name ("LNM$SYSTEM_TABLE", "SYS$NODE", buf, size)) {
  2537. X    char *p;
  2538. X    while ((p = strrchr (buf, ':')))
  2539. X        *p = '\0';
  2540. X    return 0;
  2541. X    }
  2542. X    return EOF;
  2543. X}
  2544. X
  2545. X#ifndef MAKE_EMAIL_ADDRESS
  2546. X#define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
  2547. X#endif
  2548. X
  2549. struct hostent *
  2550. gethostbynameoraddr (hostname)
  2551. char *hostname;
  2552. X{
  2553. X    if (isdigit (*hostname)) {
  2554. X    static struct hostent x;
  2555. X    static char *alias_list[1];
  2556. X    static unsigned long *addr_list[2];
  2557. X    static unsigned long ip_address;
  2558. X
  2559. X    ip_address = inet_addr (hostname);
  2560. X
  2561. X    addr_list[0] = &ip_address;
  2562. X    addr_list[1] = NULL;
  2563. X    alias_list[0] = NULL;
  2564. X
  2565. X    x.h_name = hostname;
  2566. X    x.h_aliases = alias_list;
  2567. X    x.h_addrtype = AF_INET;
  2568. X    x.h_length = sizeof (unsigned long);
  2569. X    x.h_addr_list = (char **) addr_list;
  2570. X    return &x;
  2571. X    }
  2572. X    return gethostbyname (hostname);
  2573. X}
  2574. X
  2575. void 
  2576. sysdep()
  2577. X{
  2578. X    struct passwd *pwd;
  2579. X    char *p;
  2580. X    struct hostent *hp;
  2581. X    char *getenv ();
  2582. X    char nodename[100];
  2583. X
  2584. X    get_decnet_node_name (nodename, sizeof(nodename));
  2585. X    gethostname (hostname, sizeof hostname);
  2586. X
  2587. X    /* get user name (will be in ALL CAPS - yikes!) */
  2588. X    cuserid (username);
  2589. X
  2590. X    hp = gethostbyname (hostname);
  2591. X    MAKE_EMAIL_ADDRESS(email_address, username, hp ? hp->h_name : hostname);
  2592. X
  2593. X    /* lower case host name and user name */
  2594. X    for (p = hostname; *p; ++p)
  2595. X    if (isupper (*p))
  2596. X        *p = tolower (*p);
  2597. X
  2598. X    for (p = username; *p; ++p)
  2599. X    if (isupper (*p))
  2600. X        *p = tolower (*p);
  2601. X}
  2602. X
  2603. X
  2604. X/*
  2605. X * Allocate a socket and bind it to a local privileged port
  2606. X * We have to be running set-uid to root to do this.
  2607. X */
  2608. X
  2609. int
  2610. get_priv_tcp_socket ()
  2611. X{
  2612. X    int fd;
  2613. X    int port;
  2614. X    struct sockaddr_in s;
  2615. X
  2616. X    if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) {
  2617. X    perror ("socket");
  2618. X    return EOF;
  2619. X    }
  2620. X    for (port = IPPORT_RESERVED-1; port > IPPORT_RESERVED / 2; port--) {
  2621. X    extern int errno;
  2622. X    s.sin_family = AF_INET;
  2623. X    s.sin_addr.s_addr = INADDR_ANY;
  2624. X    s.sin_port = htons (port);
  2625. X    if (bind (fd, (struct sockaddr *) &s, sizeof (s)) == 0)
  2626. X        return fd;
  2627. X    if (errno == EACCES) {
  2628. X        fprintf (stderr, "lpr warning: bind: cannot bind to privileged port\n");
  2629. X        return fd;
  2630. X    }
  2631. X    }
  2632. X    close (fd);
  2633. X    return EOF;
  2634. X}
  2635. X
  2636. X/*
  2637. X * Open a TCP connection to an lpd-server.
  2638. X * This requires that this program be run set-uid to root in order to be able
  2639. X * to bind a socket to a privileged port.
  2640. X */
  2641. X
  2642. int
  2643. open_lpd (server)
  2644. char *server;
  2645. X{
  2646. X    int fd;
  2647. X    int i;
  2648. X    int last_connect_failed;
  2649. X    struct hostent *hp;
  2650. X    struct servent *sp;
  2651. X    struct sockaddr_in s;
  2652. X    void bcopy ();
  2653. X
  2654. X    if (server == NULL || *server == '\0') {
  2655. X    fprintf (stderr, "lpr: no server host was specified.\n");
  2656. X    fprintf (stderr, "     Supply one with the -S option, or\n");
  2657. X    fprintf (stderr, "     by defining the LPD_SERVER logical name\n");
  2658. X    return EOF;
  2659. X    }
  2660. X    if ((hp = gethostbynameoraddr (server)) == NULL) {
  2661. X    fprintf (stderr, "lpr: can't find network address for %s\n",
  2662. X         server);
  2663. X    fflush (stderr);
  2664. X    return EOF;
  2665. X    }
  2666. X
  2667. X    s.sin_family = AF_INET;
  2668. X#if 1
  2669. X    /* some bug in the VMS C optimizer seems to require this */
  2670. X    s.sin_port = htons (515);
  2671. X#else
  2672. X    if ((sp = getservbyname ("printer", "tcp")) == NULL)
  2673. X    s.sin_port = htons (515);
  2674. X    else
  2675. X    s.sin_port = sp->s_port;
  2676. X#endif
  2677. X
  2678. X    /*
  2679. X     * On some systems h_addr is a macro that is defined to be h_addr_list[0]
  2680. X     * On other (ancient) systems, h_addr is a member of the hostent structure.
  2681. X     * So if h_addr is defined as a macro, then we must have the list...
  2682. X     */
  2683. X
  2684. X#ifdef h_addr
  2685. X    for (i = 0; hp->h_addr_list[i] ; ++i) {
  2686. X    fd = get_priv_tcp_socket ();
  2687. X    disable_special_privileges ();
  2688. X    if (fd < 0)
  2689. X        return EOF;
  2690. X    bcopy ((char *) hp->h_addr_list[i], (char *) &s.sin_addr,
  2691. X           sizeof (s.sin_addr));
  2692. X    if (debug)
  2693. X        fprintf (stderr, "Trying %s...", inet_ntoa (s.sin_addr));
  2694. X    last_connect_failed = 0; /* "I'm ashamed of this." - SMK */
  2695. X    if (connect (fd, &s, sizeof s) == 0) {
  2696. X        if (debug)
  2697. X        fprintf (stderr, "open\n");
  2698. X        break;
  2699. X    }
  2700. X    else {
  2701. X        close (fd);        /* reuse fd */
  2702. X        if (debug)
  2703. X        perror ("");
  2704. X        last_connect_failed = 1;
  2705. X    }
  2706. X    }
  2707. X    if (last_connect_failed) {
  2708. X    perror ("connect");
  2709. X    return EOF;
  2710. X    }
  2711. X#else
  2712. X    fd = get_priv_tcp_socket ();
  2713. X    disable_special_privileges ();
  2714. X    if (fd < 0)
  2715. X    return EOF;
  2716. X    bcopy ((char *) hp->h_addr, (char *) &s.sin_addr, sizeof(s.sin_addr));
  2717. X    if (connect (fd, &s, sizeof s) < 0) {
  2718. X    perror ("connect");
  2719. X    close (fd);
  2720. X    return EOF;
  2721. X    }
  2722. X#endif
  2723. X
  2724. X    max_net_read = max_net_write = 32767;
  2725. X    return fd;
  2726. X}
  2727. X
  2728. X/*
  2729. X * initialized data structures for disable_special_privileges (), below
  2730. X */
  2731. X
  2732. int curr_proc_privs[2] = { 0, 0 }; /* current (image+perm) proc privs */
  2733. int perm_proc_privs[2] = { 0, 0 }; /* permanent process privileges */
  2734. int privs_length = 2;
  2735. X
  2736. struct item_list jpi_item_list[] = {
  2737. X    { sizeof curr_proc_privs, JPI$_CURPRIV,  curr_proc_privs, &privs_length },
  2738. X    { sizeof perm_proc_privs, JPI$_PROCPRIV, perm_proc_privs, &privs_length },
  2739. X    { 0 },
  2740. X};
  2741. X
  2742. X/*
  2743. X * Turn off set-uid privileges.
  2744. X * We have to have either SYSPRV or BYPASS privilege to bind to a privileged
  2745. X * port.  In order to minimize the security risk, we want to turn off these
  2746. X * privileges as soon as we acquire the binding.  This function turns off
  2747. X * all privileges that are specific to this image.
  2748. X */
  2749. X
  2750. static int
  2751. disable_special_privileges ()
  2752. X{
  2753. X    int status;
  2754. X    int privs_to_disable[2];
  2755. X
  2756. X    /* get current privileges */
  2757. X    if ((status = sys$getjpiw (0, 0, 0, jpi_item_list, 0, 0, 0)) != SS$_NORMAL)
  2758. X    exit (status);
  2759. X    /*
  2760. X     * Turn off any privileges that aren't in the permanent process priv mask.
  2761. X     */
  2762. X    privs_to_disable[0] = curr_proc_privs[0] & ~perm_proc_privs[0];
  2763. X    privs_to_disable[1] = curr_proc_privs[1] & ~perm_proc_privs[1];
  2764. X
  2765. X    if ((status = sys$setprv (0, privs_to_disable, 0, 0)) != SS$_NORMAL)
  2766. X    exit (status);
  2767. X}
  2768. X
  2769. X/*
  2770. X * bcopy() is not provided by the VMS C library
  2771. X * This version is not particularly efficient, but we don't use it enough
  2772. X * here to write a better version.
  2773. X */
  2774. X
  2775. void
  2776. bcopy (src, dest, length)
  2777. register char *src, *dest;
  2778. unsigned int length;
  2779. X{
  2780. X    if (length == 0)
  2781. X    return;
  2782. X    do {
  2783. X    *dest++ = *src++;
  2784. X    } while (--length);
  2785. X}
  2786. X
  2787. X/*
  2788. X * unlink() is not provided by the VMS C library (for reasons which have
  2789. X * always eluded me).  delete() does essentially the same thing, but
  2790. X * doesn't return the same error codes as unlink.  It is, however, sufficient 
  2791. X * for our purposes.
  2792. X */
  2793. X
  2794. int
  2795. unlink (filename)
  2796. char *filename;
  2797. X{
  2798. X    return delete (filename);
  2799. X}
  2800. END_OF_FILE
  2801. if test 8256 -ne `wc -c <'vms-ucx-tcp.c'`; then
  2802.     echo shar: \"'vms-ucx-tcp.c'\" unpacked with wrong size!
  2803. fi
  2804. # end of 'vms-ucx-tcp.c'
  2805. fi
  2806. if test -f 'vms-decnet.c' -a "${1}" != "-c" ; then 
  2807.   echo shar: Will not clobber existing file \"'vms-decnet.c'\"
  2808. else
  2809. echo shar: Extracting \"'vms-decnet.c'\" \(3448 characters\)
  2810. sed "s/^X//" >'vms-decnet.c' <<'END_OF_FILE'
  2811. X/*
  2812. X * lpr interface for VAX/VMS DECnet
  2813. X */
  2814. X
  2815. X#include "common.h"
  2816. X#include "config.h"
  2817. X#include <stdio.h>
  2818. X#include <ctype.h>
  2819. X#include <lnmdef.h>
  2820. X
  2821. struct item_list {
  2822. X    unsigned short buffer_length;
  2823. X    unsigned short item_code;
  2824. X    char *buffer_address;
  2825. X    char *length_address;
  2826. X};
  2827. X
  2828. struct descrip {
  2829. X    int length;
  2830. X    char *ptr;
  2831. X};
  2832. X
  2833. X/*
  2834. X * Translate a VAX/VMS logical name, given the name we want to translate
  2835. X * and the table name we want to search with.
  2836. X */
  2837. X
  2838. int
  2839. translate_logical_name (table, name, buf, size)
  2840. char *table; char *name; char *buf; int size;
  2841. X{
  2842. X    struct descrip table_d;
  2843. X    struct descrip name_d;
  2844. X    struct item_list item_list[2];
  2845. X    int foo;
  2846. X    int status;
  2847. X
  2848. X    table_d.length = strlen (table);
  2849. X    table_d.ptr = table;
  2850. X    name_d.length = strlen (name);
  2851. X    name_d.ptr = name;
  2852. X    item_list[0].buffer_length = size - 1;
  2853. X    item_list[0].item_code = LNM$_STRING;
  2854. X    item_list[0].buffer_address = buf;
  2855. X    item_list[0].length_address = &foo;
  2856. X    item_list[1].buffer_length = 0;
  2857. X    item_list[1].item_code = 0;
  2858. X    item_list[1].buffer_address = 0;
  2859. X    item_list[1].length_address = 0;
  2860. X    status = SYS$TRNLNM (0, &table_d, &name_d, 0, item_list);
  2861. X    if ((status & 01) != 01)
  2862. X    lib$signal (status);
  2863. X    if (foo >= 0 && foo < size)
  2864. X    buf[foo] = '\0';
  2865. X    return ((status & 01) ? 0 : EOF);
  2866. X}
  2867. X
  2868. X/*
  2869. X * Determine the DECnet node name by translating the system logical name
  2870. X * SYS$NODE.  We use this function rather than the getenv() function,
  2871. X * just to make sure the user doesn't define his/her own SYS$NODE variable
  2872. X * and pretend he/she is submitting the print job from somewhere else.
  2873. X */
  2874. X
  2875. int
  2876. get_decnet_node_name (buf, size)
  2877. char *buf; int size;
  2878. X{
  2879. X    char *strrchr ();
  2880. X    if (!translate_logical_name ("LNM$SYSTEM_TABLE", "SYS$NODE", buf, size)) {
  2881. X    char *p;
  2882. X    while (p = strrchr (buf, ':'))
  2883. X        *p = '\0';
  2884. X    return 0;
  2885. X    }
  2886. X    return EOF;
  2887. X}
  2888. X
  2889. X#ifndef MAKE_EMAIL_ADDRESS
  2890. X#define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
  2891. X#endif
  2892. X
  2893. void 
  2894. sysdep()
  2895. X{
  2896. X    struct passwd *pwd;
  2897. X    char *p;
  2898. X    struct hostent *hp;
  2899. X    char *getenv ();
  2900. X    char nodename[100];
  2901. X
  2902. X    get_decnet_node_name (nodename, sizeof(nodename));
  2903. X    strcpy (hostname, nodename);
  2904. X
  2905. X    /* get user name (will be in ALL CAPS - yikes!) */
  2906. X    cuserid (username);
  2907. X
  2908. X    MAKE_EMAIL_ADDRESS(email_address, username, hostname);
  2909. X
  2910. X    /* lower case host name and user name */
  2911. X    for (p = hostname; *p; ++p)
  2912. X    if (isupper (*p))
  2913. X        *p = tolower (*p);
  2914. X
  2915. X    for (p = username; *p; ++p)
  2916. X    if (isupper (*p))
  2917. X        *p = tolower (*p);
  2918. X}
  2919. X
  2920. X/*
  2921. X * Open a DECnet connection to an lpd-server.
  2922. X */
  2923. X
  2924. int
  2925. open_lpd (server)
  2926. char *server;
  2927. X{
  2928. X    int fd;
  2929. X    char buf[512];
  2930. X
  2931. X    if (server == NULL || *server == '\0') {
  2932. X    fprintf (stderr, "lpr: no printer server host is defined\n");
  2933. X    fprintf (stderr, "     Either specify one using -S, or\n");
  2934. X    fprintf (stderr, "     using the logical name LPD_SERVER.\n");
  2935. X    return EOF;
  2936. X    }
  2937. X    sprintf (buf, "%s::\"223=\"", server);
  2938. X    if ((fd = open (buf, 2)) < 0) {
  2939. X    fprintf (stderr, "cannot open remote DECnet object '%s'\n", buf);
  2940. X    perror ("");
  2941. X    }
  2942. X    max_net_read = max_net_write = 512;
  2943. X    return fd;
  2944. X}
  2945. X
  2946. X/*
  2947. X * unlink() is not provided by the VMS C library (for reasons which have
  2948. X * always eluded me).  delete() does essentially the same thing, but
  2949. X * doesn't return the same error codes as unlink.  It is, however, sufficient 
  2950. X * for our purposes.
  2951. X */
  2952. X
  2953. int
  2954. unlink (filename)
  2955. char *filename;
  2956. X{
  2957. X    return delete (filename);
  2958. X}
  2959. X
  2960. END_OF_FILE
  2961. if test 3448 -ne `wc -c <'vms-decnet.c'`; then
  2962.     echo shar: \"'vms-decnet.c'\" unpacked with wrong size!
  2963. fi
  2964. # end of 'vms-decnet.c'
  2965. fi
  2966. if test -f 'vms-win-tcp.c' -a "${1}" != "-c" ; then 
  2967.   echo shar: Will not clobber existing file \"'vms-win-tcp.c'\"
  2968. else
  2969. echo shar: Extracting \"'vms-win-tcp.c'\" \(9046 characters\)
  2970. sed "s/^X//" >'vms-win-tcp.c' <<'END_OF_FILE'
  2971. X/*
  2972. X * lpr interface for Wollengong's WIN/TCP for VAX/VMS
  2973. X */
  2974. X
  2975. X#include "common.h"
  2976. X#include "config.h"
  2977. X#include <stdio.h>
  2978. X#include <ctype.h>
  2979. X/*
  2980. X * Our (old) version of WIN/TCP has definitions in its include files that
  2981. X * conflict with the definitions in the VMS system library include files.
  2982. X * So I have pulled out only those definitions I need for this module.
  2983. X */
  2984. X/* #include "twg$tcp:[netdist.include.sys]types.h" */
  2985. typedef unsigned short u_short;
  2986. typedef unsigned long u_long;
  2987. typedef char * caddr_t;
  2988. X/* #include "twg$tcp:[netdist.include.sys]stat.h" */
  2989. X#include "twg$tcp:[netdist.include]netdb.h"
  2990. X#include "twg$tcp:[netdist.include.sys]socket.h"
  2991. X/*
  2992. X * WIN/TCP's errno.h puts errno in a different program segment than
  2993. X * the one in sys$library.  The only define we use here is EACCES
  2994. X * which is the same in both places.  If you are running an old
  2995. X * version of VMS, you might have to change this a bit.
  2996. X */
  2997. X/* #include "twg$tcp:[netdist.include]errno.h" */
  2998. X#include <errno.h>
  2999. X#include "twg$tcp:[netdist.include.netinet]in.h"
  3000. X#include <prvdef.h>
  3001. X#include <jpidef.h>
  3002. X#include <ssdef.h>
  3003. X#include <lnmdef.h>
  3004. X
  3005. struct item_list {
  3006. X    unsigned short buffer_length;
  3007. X    unsigned short item_code;
  3008. X    char *buffer_address;
  3009. X    char *length_address;
  3010. X};
  3011. X
  3012. struct descrip {
  3013. X    int length;
  3014. X    char *ptr;
  3015. X};
  3016. X
  3017. X/*
  3018. X * Translate a VAX/VMS logical name, given the name we want to translate
  3019. X * and the table name we want to search with.
  3020. X */
  3021. X
  3022. int
  3023. translate_logical_name (table, name, buf, size)
  3024. char *table; char *name; char *buf; int size;
  3025. X{
  3026. X    struct descrip table_d;
  3027. X    struct descrip name_d;
  3028. X    struct item_list item_list[2];
  3029. X    int foo;
  3030. X    int status;
  3031. X
  3032. X    table_d.length = strlen (table);
  3033. X    table_d.ptr = table;
  3034. X    name_d.length = strlen (name);
  3035. X    name_d.ptr = name;
  3036. X    item_list[0].buffer_length = size - 1;
  3037. X    item_list[0].item_code = LNM$_STRING;
  3038. X    item_list[0].buffer_address = buf;
  3039. X    item_list[0].length_address = &foo;
  3040. X    item_list[1].buffer_length = 0;
  3041. X    item_list[1].item_code = 0;
  3042. X    item_list[1].buffer_address = 0;
  3043. X    item_list[1].length_address = 0;
  3044. X    status = SYS$TRNLNM (0, &table_d, &name_d, 0, item_list);
  3045. X    if ((status & 01) != 01)
  3046. X    lib$signal (status);
  3047. X    if (foo >= 0 && foo < size)
  3048. X    buf[foo] = '\0';
  3049. X    return ((status & 01) ? 0 : EOF);
  3050. X}
  3051. X
  3052. X/*
  3053. X * Determine the DECnet node name by translating the system logical name
  3054. X * SYS$NODE.  We use this function rather than the getenv() function,
  3055. X * just to make sure the user doesn't define his/her own SYS$NODE variable
  3056. X * and pretend he/she is submitting the print job from somewhere else.
  3057. X */
  3058. X
  3059. int
  3060. get_decnet_node_name (buf, size)
  3061. char *buf; int size;
  3062. X{
  3063. X    
  3064. X    if (!translate_logical_name ("LNM$SYSTEM_TABLE", "SYS$NODE", buf, size)) {
  3065. X    char *p;
  3066. X    while ((p = strrchr (buf, ':')))
  3067. X        *p = '\0';
  3068. X    return 0;
  3069. X    }
  3070. X    return EOF;
  3071. X}
  3072. X
  3073. X#ifndef MAKE_EMAIL_ADDRESS
  3074. X#define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
  3075. X#endif
  3076. X
  3077. struct hostent *
  3078. gethostbynameoraddr (hostname)
  3079. char *hostname;
  3080. X{
  3081. X    if (isdigit (*hostname)) {
  3082. X    static struct hostent x;
  3083. X    static char *alias_list[1];
  3084. X    static unsigned long *addr_list[2];
  3085. X    static unsigned long ip_address;
  3086. X
  3087. X    ip_address = inet_addr (hostname);
  3088. X
  3089. X    addr_list[0] = &ip_address;
  3090. X    addr_list[1] = NULL;
  3091. X    alias_list[0] = NULL;
  3092. X
  3093. X    x.h_name = hostname;
  3094. X    x.h_aliases = alias_list;
  3095. X    x.h_addrtype = AF_INET;
  3096. X    x.h_length = sizeof (unsigned long);
  3097. X    x.h_addr_list = (char **) addr_list;
  3098. X    return &x;
  3099. X    }
  3100. X    return gethostbyname (hostname);
  3101. X}
  3102. X
  3103. X
  3104. void sysdep()
  3105. X{
  3106. X    struct passwd *pwd;
  3107. X    char *p;
  3108. X    struct hostent *hp;
  3109. X    char *getenv ();
  3110. X    char nodename[100];
  3111. X
  3112. X    get_decnet_node_name (nodename, sizeof(nodename));
  3113. X    gethostname (hostname, sizeof hostname);
  3114. X
  3115. X    /* get user name (will be in ALL CAPS - yikes!) */
  3116. X    cuserid (username);
  3117. X
  3118. X    hp = gethostbyname (hostname);
  3119. X    MAKE_EMAIL_ADDRESS(email_address, username, hp ? hp->h_name : hostname);
  3120. X
  3121. X    /* lower case host name and user name */
  3122. X    for (p = hostname; *p; ++p)
  3123. X    if (isupper (*p))
  3124. X        *p = tolower (*p);
  3125. X
  3126. X    for (p = username; *p; ++p)
  3127. X    if (isupper (*p))
  3128. X        *p = tolower (*p);
  3129. X}
  3130. X
  3131. X
  3132. X/*
  3133. X * Allocate a socket and bind it to a local privileged port
  3134. X * We have to be running set-uid to root to do this.
  3135. X */
  3136. X
  3137. int
  3138. get_priv_tcp_socket ()
  3139. X{
  3140. X    int fd;
  3141. X    int port;
  3142. X    struct sockaddr_in s;
  3143. X
  3144. X    if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) {
  3145. X    perror ("socket");
  3146. X    return EOF;
  3147. X    }
  3148. X    for (port = IPPORT_RESERVED-1; port > IPPORT_RESERVED / 2; port--) {
  3149. X    extern int errno;
  3150. X    s.sin_family = AF_INET;
  3151. X    s.sin_addr.s_addr = INADDR_ANY;
  3152. X    s.sin_port = htons (port);
  3153. X    if (bind (fd, (struct sockaddr *) &s, sizeof (s)) == 0)
  3154. X        return fd;
  3155. X    if (errno == EACCES) {
  3156. X        fprintf (stderr, "lpr warning: bind: cannot bind to privileged port\n");
  3157. X        return fd;
  3158. X    }
  3159. X    }
  3160. X    close (fd);
  3161. X    return EOF;
  3162. X}
  3163. X
  3164. X/*
  3165. X * Open a TCP connection to an lpd-server.
  3166. X * This requires that this program be run set-uid to root in order to be able
  3167. X * to bind a socket to a privileged port.
  3168. X */
  3169. X
  3170. int
  3171. open_lpd (server)
  3172. char *server;
  3173. X{
  3174. X    int fd;
  3175. X    int i;
  3176. X    int last_connect_failed;
  3177. X    struct hostent *hp;
  3178. X    struct servent *sp;
  3179. X    struct sockaddr_in s;
  3180. X    void bcopy ();
  3181. X
  3182. X    if (server == NULL || *server == '\0') {
  3183. X    fprintf (stderr, "lpr: no server host was specified.\n");
  3184. X    fprintf (stderr, "     Supply one with the -S option, or\n");
  3185. X    fprintf (stderr, "     by defining the LPD_SERVER logical name\n");
  3186. X    return EOF;
  3187. X    }
  3188. X    if ((hp = gethostbynameoraddr (server)) == NULL) {
  3189. X    fprintf (stderr, "lpr: can't find network address for %s\n",
  3190. X         server);
  3191. X    fflush (stderr);
  3192. X    return EOF;
  3193. X    }
  3194. X
  3195. X    s.sin_family = AF_INET;
  3196. X#if 1
  3197. X    /* some bug in the VMS C optimizer seems to require this */
  3198. X    s.sin_port = htons (515);
  3199. X#else
  3200. X    if ((sp = getservbyname ("printer", "tcp")) == NULL)
  3201. X    s.sin_port = htons (515);
  3202. X    else
  3203. X    s.sin_port = sp->s_port;
  3204. X#endif
  3205. X
  3206. X    /*
  3207. X     * On some systems h_addr is a macro that is defined to be h_addr_list[0]
  3208. X     * On other (ancient) systems, h_addr is a member of the hostent structure.
  3209. X     * So if h_addr is defined as a macro, then we must have the list...
  3210. X     */
  3211. X
  3212. X#ifdef h_addr
  3213. X    for (i = 0; hp->h_addr_list[i] ; ++i) {
  3214. X    fd = get_priv_tcp_socket ();
  3215. X    disable_special_privileges ();
  3216. X    if (fd < 0)
  3217. X        return EOF;
  3218. X    bcopy ((char *) hp->h_addr_list[i], (char *) &s.sin_addr,
  3219. X           sizeof (s.sin_addr));
  3220. X    if (debug)
  3221. X        fprintf (stderr, "Trying %s...", inet_ntoa (s.sin_addr));
  3222. X    last_connect_failed = 0; /* "I'm ashamed of this." - SMK */
  3223. X    if (connect (fd, &s, sizeof s) == 0) {
  3224. X        if (debug)
  3225. X        fprintf (stderr, "open\n");
  3226. X        break;
  3227. X    }
  3228. X    else {
  3229. X        close (fd);        /* reuse fd */
  3230. X        if (debug)
  3231. X        perror ("");
  3232. X        last_connect_failed = 1;
  3233. X    }
  3234. X    }
  3235. X    if (last_connect_failed) {
  3236. X    perror ("connect");
  3237. X    return EOF;
  3238. X    }
  3239. X#else
  3240. X    fd = get_priv_tcp_socket ();
  3241. X    disable_special_privileges ();
  3242. X    if (fd < 0)
  3243. X    return EOF;
  3244. X    bcopy ((char *) hp->h_addr, (char *) &s.sin_addr, sizeof(s.sin_addr));
  3245. X    if (connect (fd, &s, sizeof s) < 0) {
  3246. X    perror ("connect");
  3247. X    close (fd);
  3248. X    return EOF;
  3249. X    }
  3250. X#endif
  3251. X
  3252. X    max_net_read = max_net_write = 32767;
  3253. X    return fd;
  3254. X}
  3255. X
  3256. X/*
  3257. X * initialized data structures for disable_special_privileges (), below
  3258. X */
  3259. X
  3260. int curr_proc_privs[2] = { 0, 0 }; /* current (image+perm) proc privs */
  3261. int perm_proc_privs[2] = { 0, 0 }; /* permanent process privileges */
  3262. int privs_length = 2;
  3263. X
  3264. struct item_list jpi_item_list[] = {
  3265. X    { sizeof curr_proc_privs, JPI$_CURPRIV,  curr_proc_privs, &privs_length },
  3266. X    { sizeof perm_proc_privs, JPI$_PROCPRIV, perm_proc_privs, &privs_length },
  3267. X    { 0 },
  3268. X};
  3269. X
  3270. X/*
  3271. X * Turn off set-uid privileges.
  3272. X * We have to have either SYSPRV or BYPASS privilege to bind to a privileged
  3273. X * port.  In order to minimize the security risk, we want to turn off these
  3274. X * privileges as soon as we acquire the binding.  This function turns off
  3275. X * all privileges that are specific to this image.
  3276. X */
  3277. X
  3278. int
  3279. disable_special_privileges ()
  3280. X{
  3281. X    int status;
  3282. X    int privs_to_disable[2];
  3283. X
  3284. X    /* get current privileges */
  3285. X    if ((status = sys$getjpiw (0, 0, 0, jpi_item_list, 0, 0, 0)) != SS$_NORMAL)
  3286. X    exit (status);
  3287. X    /*
  3288. X     * Turn off any privileges that aren't in the permanent process priv mask.
  3289. X     */
  3290. X    privs_to_disable[0] = curr_proc_privs[0] & ~perm_proc_privs[0];
  3291. X    privs_to_disable[1] = curr_proc_privs[1] & ~perm_proc_privs[1];
  3292. X
  3293. X    if ((status = sys$setprv (0, privs_to_disable, 0, 0)) != SS$_NORMAL)
  3294. X    exit (status);
  3295. X}
  3296. X
  3297. X/*
  3298. X * bcopy() is not provided by the VMS C library
  3299. X * This version is not particularly efficient, but we don't use it enough
  3300. X * here to write a better version.
  3301. X */
  3302. X
  3303. void
  3304. bcopy (src, dest, length)
  3305. register char *src, *dest;
  3306. unsigned int length;
  3307. X{
  3308. X    if (length == 0)
  3309. X    return;
  3310. X    do {
  3311. X    *dest++ = *src++;
  3312. X    } while (--length);
  3313. X}
  3314. X
  3315. X/*
  3316. X * unlink() is not provided by the VMS C library (for reasons which have
  3317. X * always eluded me).  delete() does essentially the same thing, but
  3318. X * doesn't return the same error codes as unlink.  It is, however, sufficient 
  3319. X * for our purposes.
  3320. X */
  3321. X
  3322. int
  3323. unlink (filename)
  3324. char *filename;
  3325. X{
  3326. X    return delete (filename);
  3327. X}
  3328. END_OF_FILE
  3329. if test 9046 -ne `wc -c <'vms-win-tcp.c'`; then
  3330.     echo shar: \"'vms-win-tcp.c'\" unpacked with wrong size!
  3331. fi
  3332. # end of 'vms-win-tcp.c'
  3333. fi
  3334. if test -f 'descrip.mms' -a "${1}" != "-c" ; then 
  3335.   echo shar: Will not clobber existing file \"'descrip.mms'\"
  3336. else
  3337. echo shar: Extracting \"'descrip.mms'\" \(739 characters\)
  3338. sed "s/^X//" >'descrip.mms' <<'END_OF_FILE'
  3339. X# Makefile for VMS MMS (Module Management System)
  3340. X# You may have to modify this file slightly to work on other VMS make clones
  3341. X#
  3342. X# pick a back-end driver from one of the following:
  3343. X#
  3344. X#DRIVER=vms-ucx-tcp.obj        # VMS Ultrix Connection
  3345. X#DRIVER=vms-win-tcp.obj        # VMS WIN/TCP
  3346. DRIVER=vms-decnet.obj        # DECnet-VAX (requires gateway on UNIX)
  3347. X#
  3348. X# pick a library to go with the driver
  3349. X#
  3350. X#LIBRARY=sys$library:ucx$ipc.olb/lib        # VMS Ultrix Connection
  3351. X#LIBRARY=twg$tcp:[netdist.lib]twglib.olb/lib    # VMS WIN/TCP
  3352. LIBRARY=sys$library:vaxcrtl.olb/lib        # dummy for DECnet
  3353. X#
  3354. X#
  3355. CFLAGS=/debug
  3356. LDFLAGS=
  3357. X#
  3358. lpr.exe : lpr.obj $(DRIVER)
  3359. X    LINK $(LDFLAGS) lpr.obj,$(DRIVER),$(LIBRARY)
  3360. X
  3361. lpr.obj : lpr.c config.h
  3362. X    $(CC) $(CFLAGS) lpr.c
  3363. X
  3364. X
  3365. clean :
  3366. X    del lpr.exe;*,*.obj;*
  3367. END_OF_FILE
  3368. if test 739 -ne `wc -c <'descrip.mms'`; then
  3369.     echo shar: \"'descrip.mms'\" unpacked with wrong size!
  3370. fi
  3371. # end of 'descrip.mms'
  3372. fi
  3373. if test -f 'dnet-lpd-gw.c' -a "${1}" != "-c" ; then 
  3374.   echo shar: Will not clobber existing file \"'dnet-lpd-gw.c'\"
  3375. else
  3376. echo shar: Extracting \"'dnet-lpd-gw.c'\" \(5508 characters\)
  3377. sed "s/^X//" >'dnet-lpd-gw.c' <<'END_OF_FILE'
  3378. X/*
  3379. X * line printer daemon gateway for DECnet
  3380. X *
  3381. X * Listens on a DECnet port and copies packets to/from the local
  3382. X * Berkeley line printer daemon.
  3383. X */
  3384. X
  3385. X#include <stdio.h>
  3386. X#include <sys/types.h>
  3387. X#include <sys/socket.h>
  3388. X#include <netinet/in.h>
  3389. X#include <sys/un.h>
  3390. X#include <netdb.h>
  3391. X#include <ctype.h>
  3392. X#include <errno.h>
  3393. X#define MAIN_PROGRAM
  3394. X#include "common.h"
  3395. X
  3396. X
  3397. char *DECnet_remoteNode;
  3398. char *DECnet_remoteUser;
  3399. X
  3400. void
  3401. dump_buf (fp, prefix, buf, size)
  3402. unsigned char *prefix, *buf;
  3403. int size;
  3404. XFILE *fp;
  3405. X{
  3406. X    int i;
  3407. X    fprintf (fp, "%s ", prefix);
  3408. X    for (i = 0; i < size; ++i)
  3409. X    if (buf[i] >= ' ' && buf[i] <= '~')
  3410. X        putc (buf[i], fp);
  3411. X    else if (buf[i] == '\n')
  3412. X        fprintf (fp, "\\n");
  3413. X    else
  3414. X        fprintf (fp, "\\%03o", buf[i] & 0377);
  3415. X    putc ('\n', fp);
  3416. X    fflush (fp);
  3417. X}
  3418. X
  3419. char *
  3420. strsave (s)
  3421. char *s;
  3422. X{
  3423. X    char *malloc ();
  3424. X    char *p;
  3425. X    if (s == NULL)
  3426. X    return NULL;
  3427. X    if ((p = malloc (strlen (s) + 1)) == NULL)
  3428. X    return NULL;
  3429. X    strcpy (p, s);
  3430. X    return p;
  3431. X}
  3432. X
  3433. X
  3434. X#ifdef sun
  3435. X/*
  3436. X * accept code for SunLink DNI
  3437. X */
  3438. X
  3439. X#include <sys/ioctl.h>
  3440. X#include <netdni/dni.h>
  3441. X
  3442. int
  3443. accept_decnet_connection ()
  3444. X{
  3445. X    OpenBlock open_block;
  3446. X    SessionData session_data;
  3447. X    int dnet_fd;
  3448. X
  3449. X    dnet_fd = 3;
  3450. X    if (ioctl (dnet_fd, SES_GET_AI, &open_block) < 0) {
  3451. X    fprintf (stderr, "dnet-lpd: can't get access control information\n");
  3452. X    fflush (stderr);
  3453. X    return EOF;
  3454. X    }
  3455. X    DECnet_remoteNode = strsave (open_block.op_node_name);
  3456. X    DECnet_remoteUser = strsave (open_block.op_userid);
  3457. X    if (ioctl (dnet_fd, SES_ACCEPT, &session_data) < 0) {
  3458. X    fprintf (stderr, "dnet-lpd: can't accept inbound connection\n");
  3459. X    fflush (stderr);
  3460. X    return EOF;
  3461. X    }
  3462. X    return dnet_fd;
  3463. X}
  3464. X#endif
  3465. X
  3466. X
  3467. X#ifdef ultrix
  3468. X/*
  3469. X * accept code for DECnet-Ultrix (untested)
  3470. X */
  3471. X
  3472. X#include <netdnet/dn.h>
  3473. X
  3474. int
  3475. accept_decnet_connection ()
  3476. X{
  3477. X    struct accessdata_dn acc_data;
  3478. X    int dnet_fd = 0;
  3479. X
  3480. X    setsockopt (dnet_fd, DNPROTO_NSP, DSO_CONACCESS, &acc_data,
  3481. X        sizeof (acc_data));
  3482. X    DECnet_remoteNode = strsave (getenv ("REMNODE"));
  3483. X    DECnet_remoteUser = strsave (getenv ("REMUSER"));
  3484. X    setsockopt (dnet_fd, DNPROTO_NSP, DSO_CONACCEPT, 0, 0);
  3485. X    return dnet_fd;
  3486. X}
  3487. X#endif
  3488. X
  3489. int
  3490. x_read (fd, buf, size)
  3491. int fd; char *buf; unsigned size;
  3492. X{
  3493. X    int nread = read (fd, (char *) buf, size);
  3494. X    char prefix[10];
  3495. X    sprintf (prefix, "<%d<", fd);
  3496. X    if (debug)
  3497. X    dump_buf (stderr, prefix, buf, nread);
  3498. X    return nread;
  3499. X}
  3500. X
  3501. int
  3502. x_write (fd, buf, size)
  3503. int fd; char *buf; unsigned size;
  3504. X{
  3505. X    char prefix[10];
  3506. X    sprintf (prefix, ">%d>", fd);
  3507. X    if (debug)
  3508. X    dump_buf (stderr, prefix, buf, size);
  3509. X    return write (fd, (char *) buf, size);
  3510. X}
  3511. X
  3512. int
  3513. y_read (fd, buf, size)
  3514. int fd; char *buf; unsigned size;
  3515. X{
  3516. X    int nread = read (fd, (char *) buf, size);
  3517. X    if (debug)
  3518. X    fprintf (stderr, "<%d< (%d bytes)\n", fd, nread);
  3519. X    return nread;
  3520. X}
  3521. X
  3522. int
  3523. y_write (fd, buf, size)
  3524. int fd; char *buf; unsigned size;
  3525. X{
  3526. X    if (debug)
  3527. X    fprintf (stderr, ">%d> (%d bytes)\n", fd, size);
  3528. X    return write (fd, (char *) buf, size);
  3529. X}
  3530. X
  3531. do_gateway (dnet_fd, tcp_fd)
  3532. int dnet_fd, tcp_fd;
  3533. X{
  3534. X    char buf[512];
  3535. X    int nread;
  3536. X
  3537. X    while ((nread = x_read (dnet_fd, buf, sizeof buf)) > 0) {
  3538. X    switch (*buf) {
  3539. X    case '\02':        /* receive a printer job */
  3540. X        x_write (tcp_fd, buf, nread);
  3541. X        nread = x_read (tcp_fd, buf, sizeof buf);
  3542. X        if (nread > 0) {
  3543. X        x_write (dnet_fd, buf, nread);
  3544. X        receive_job (dnet_fd, tcp_fd);
  3545. X        }
  3546. X        else
  3547. X        exit (0);
  3548. X        break;
  3549. X    case '\01':        /* print any waiting jobs */
  3550. X    case '\03':        /* display queue state (short) */
  3551. X    case '\04':        /* display queue state (long) */
  3552. X    case '\05':        /* remove jobs */
  3553. X    default:
  3554. X        x_write (tcp_fd, buf, nread);
  3555. X        while ((nread = x_read (tcp_fd, buf, sizeof buf)) > 0)
  3556. X        x_write (dnet_fd, buf, nread);
  3557. X        exit (0);
  3558. X    }
  3559. X    }
  3560. X}
  3561. X
  3562. receive_job (dnet_fd, tcp_fd)
  3563. int dnet_fd, tcp_fd;
  3564. X{
  3565. X    char buf[512];
  3566. X    int nread;
  3567. X    int count;
  3568. X
  3569. X    while ((nread = x_read (dnet_fd, buf, sizeof buf)) > 0) {
  3570. X    switch (*buf) {
  3571. X    case '\01':
  3572. X    default:
  3573. X        x_write (tcp_fd, buf, nread);
  3574. X        nread = x_read (tcp_fd, buf, sizeof buf);
  3575. X        if (nread > 0)
  3576. X        x_write (dnet_fd, buf, nread);
  3577. X        else
  3578. X        exit (0);
  3579. X    case '\02':        /* send control file */
  3580. X    case '\03':        /* send data file */
  3581. X        count = atoi (buf + 1); /* length of control file */
  3582. X        /* copy command to lpd ; get response*/
  3583. X        x_write (tcp_fd, buf, nread);    
  3584. X        nread = x_read (tcp_fd, buf, sizeof buf);
  3585. X        if (nread > 0)
  3586. X        x_write (dnet_fd, buf, nread);
  3587. X        else
  3588. X        exit (0);
  3589. X        copy_file (dnet_fd, tcp_fd, count);
  3590. X    }
  3591. X    }
  3592. X}
  3593. X
  3594. copy_file (src, dest, size)
  3595. int  src, dest, size;
  3596. X{
  3597. X    int nread;
  3598. X    char buf[512];
  3599. X
  3600. X    while (size > 0) {
  3601. X    if ((nread = y_read (src, buf, sizeof buf)) > 0) {
  3602. X        y_write (dest, buf, nread);
  3603. X        size -= nread;
  3604. X    }
  3605. X    else
  3606. X        break;
  3607. X    }
  3608. X    if (size > 0) {
  3609. X    int x;
  3610. X    
  3611. X    bzero (buf, sizeof buf);
  3612. X    while (size > 0) {
  3613. X        x = size > 512 ? 512 : size;
  3614. X        y_write (dest, buf, x);
  3615. X        size -= x;
  3616. X    }
  3617. X    }
  3618. X    nread = x_read (src, buf, sizeof buf); /* should be a NUL octet */
  3619. X    x_write (dest, buf, nread);
  3620. X    nread = x_read (dest, buf, sizeof buf); /* acknowlegement */
  3621. X    x_write (src, buf, nread);
  3622. X}
  3623. X
  3624. int debug = 0;
  3625. X
  3626. main (argc, argv)
  3627. char **argv;
  3628. X{
  3629. X    int dnet_fd, tcp_fd;
  3630. X    if (debug)
  3631. X    freopen ("/tmp/dnet-lpd-gw.log", "a", stderr);
  3632. X
  3633. X    if ((dnet_fd = accept_decnet_connection ()) < 0) {
  3634. X    fprintf (stderr, "DECnet accept failed, exiting\n");
  3635. X    exit (1);
  3636. X    }
  3637. X    if ((tcp_fd = open_lpd ("localhost")) < 0) {
  3638. X    fprintf (stderr, "TCP open failed, exiting\n");
  3639. X    exit (1);
  3640. X    }
  3641. X    do_gateway (dnet_fd, tcp_fd);
  3642. X    exit (0);
  3643. X}
  3644. X
  3645. END_OF_FILE
  3646. if test 5508 -ne `wc -c <'dnet-lpd-gw.c'`; then
  3647.     echo shar: \"'dnet-lpd-gw.c'\" unpacked with wrong size!
  3648. fi
  3649. # end of 'dnet-lpd-gw.c'
  3650. fi
  3651. if test -f 'lpr.man' -a "${1}" != "-c" ; then 
  3652.   echo shar: Will not clobber existing file \"'lpr.man'\"
  3653. else
  3654. echo shar: Extracting \"'lpr.man'\" \(9647 characters\)
  3655. sed "s/^X//" >'lpr.man' <<'END_OF_FILE'
  3656. X.TH LPR 1 "21 March 1991"
  3657. X.SH NAME
  3658. lpr \- ``standalone'' interface to a remote BSD printer spooler
  3659. X.SH SYNOPSIS
  3660. X.B lpr
  3661. X[ 
  3662. X.BI \- job-option
  3663. X\&... ] [
  3664. X.BI \- file-option
  3665. X\&... ] [
  3666. X.I filename
  3667. X\&... ]
  3668. X.br
  3669. X.B lprm
  3670. X[
  3671. X.BI \-P printer
  3672. X] [
  3673. X.B \-
  3674. X]
  3675. X.I args...
  3676. X.br
  3677. X.B lpq
  3678. X[
  3679. X.BI \-P printer
  3680. X] [
  3681. X.B \-l
  3682. X]
  3683. X.I args
  3684. X.SH DESCRIPTION
  3685. This version of
  3686. X.B lpr
  3687. is an interface to a remote BSD UNIX-style printer spooler that allows
  3688. a user of a non-BSD UNIX system to print files on printers attached to
  3689. a server that supports the BSD print spooler protocol.
  3690. X.PP
  3691. When 
  3692. X.IR filename s
  3693. are supplied on the command line, 
  3694. X.B lpr
  3695. prints the named files.  If no 
  3696. X.IR filename s
  3697. appear, standard input is printed according to the supplied options.
  3698. X.PP
  3699. X.B lprm
  3700. removes the jobs specified in \fIargs\fR from the remote print queue.
  3701. The jobs must have been queued from the local host.  \fIargs\fR
  3702. consist of some combination of user names or job numbers.  If no
  3703. X\fIargs\fR are supplied, the currently active job is deleted.  The
  3704. argument ``\fB\-\fR'' is interpreted to mean ``delete all print jobs
  3705. queued by this user,'' or if invoked by root, ``delete all print jobs
  3706. queued from this host.''
  3707. X.PP
  3708. X.B lpq
  3709. prints a listing of the jobs queued for that particular printer.  The
  3710. X\fB\-l\fR option prints a more verbose listing.
  3711. X.SH ENVIRONMENT
  3712. X.B lpr
  3713. requires that the
  3714. X.B LPD_SERVER
  3715. environment variable contain the name of a printer server to which
  3716. files are spooled.  If this variable does not exist, an error message
  3717. is printed.
  3718. X.SH OPTIONS
  3719. Options fall into two general categories:  job options and file
  3720. options.  The former class of options affects an entire print job.
  3721. The latter class affects only specific files and can be overriden for
  3722. subsequent files.  For example, it is possible to print a troff file
  3723. and a plain text file in the same print job.
  3724. X.PP
  3725. Options that require arguments can be specified with or without
  3726. intervening space between the option and the argument.  Thus, either
  3727. X.BI \-P printer
  3728. or
  3729. X.B \-P
  3730. X.I printer
  3731. will work.
  3732. X.SS Job options
  3733. X.PP
  3734. These options specify parameters that affect the entire print job.  
  3735. These include:
  3736. X.TP 15
  3737. X.BI \-C jobclass
  3738. Names the job class, which will appear on the job banner page.  By default 
  3739. this is set to the local hostname.
  3740. X.TP
  3741. X.BI \-J jobtitle
  3742. Names the job title, which will appear on the job banner page when printed.  
  3743. By default this is the name of the first file named on the command line.
  3744. X.TP
  3745. X.B \-h
  3746. Tells the printer server to not print the banner page.
  3747. X.TP
  3748. X.B \-m
  3749. When the print job completes, have the printer server send a mail message
  3750. to the person who submitted the job.  This requires that your machine be able 
  3751. to receive mail addressed to 
  3752. X.IR your-user-name @ your-host-name
  3753. and that the print server be able to get it there.
  3754. X.TP
  3755. X.BI \-P printer
  3756. specifies to which printer (of those attached to the printer server)
  3757. output will be sent.
  3758. X.TP
  3759. X.BI \-q printer
  3760. The
  3761. X.B \-q
  3762. option is synonymous with the
  3763. X.B \-P
  3764. option.  This option is intended for use with VMS systems that cannot
  3765. distinguish 
  3766. X.B \-P 
  3767. from
  3768. X.B \-p.  Since 
  3769. X.B \-p 
  3770. has another meaning, 
  3771. X.B \-q
  3772. is used on
  3773. VMS to select the printer.  VMS users can also type 
  3774. X.BI \-P printer
  3775. within double quotes.
  3776. X.TP
  3777. X.B \-r
  3778. specifies that the named files are to be removed after being successfully 
  3779. transmitted to the remote printer spooler.
  3780. X.TP
  3781. X.B \-debug
  3782. Show messages sent to and from the server on the standard error output.
  3783. Not for the faint-of-heart.
  3784. X.SS File options
  3785. These options specify parameters that are particular to one or more of
  3786. the files to be printed.  These options pertain to any files that appear
  3787. to the right of the option on the command line, but they may be
  3788. overriden by specifing a different option between files.
  3789. X.PP
  3790. Only one of the file-type options
  3791. X.RB ( \-d ,
  3792. X.BR \-f ,
  3793. X.BR \-g ,
  3794. X.BR \-l ,
  3795. X.BR \-n ,
  3796. X.BR \-o ,
  3797. X.BR \-p ,
  3798. X.BR \-t ,
  3799. and
  3800. X.BR \-v )
  3801. apply to any given file.  Subsequent use of any of these options
  3802. specifies the type of each file that appears to the right of the
  3803. option, until another file-type option appears.
  3804. X.PP
  3805. In the absence of any file-type options, 
  3806. X.B lpr
  3807. X.ds tE \s-1T\s-1\dE\u\s+1X\s+1
  3808. tries to figure out what kind of file is to be printed.  It can currently
  3809. recognize \*(tE DVI files, as well as C/A/T (``classic'')
  3810. X.BR troff (1)
  3811. and PostScript files.  If the particular
  3812. kind of file is not recognized, 
  3813. X.B lpr
  3814. assumes the file is an ordinary text file.
  3815. X.TP 15
  3816. X.BI \-# number
  3817. Specifies the number of copies of each file to print.  Default is to
  3818. print one copy of each file.
  3819. X.TP
  3820. X.B \-d
  3821. XFiles that follow this option are device-independent (DVI)
  3822. files such as might be produced by \*(tE.
  3823. X.TP
  3824. X.B \-f
  3825. Tells 
  3826. X.B lpr
  3827. to expect files in FORTRAN output format, where the first
  3828. character of each line determines how to handle the ``printer
  3829. carraige'' after each line
  3830. X.RB ( SPACE =go 
  3831. to next line, 
  3832. X.RB `` + ''=overprint,
  3833. etc.)
  3834. X.TP
  3835. X.B \-g
  3836. XFiles that follow this option are expected to be in V7 UNIX 
  3837. X.BR plot (5)
  3838. format.  (Very few spoolers support this format.)
  3839. X.TP
  3840. X.B \-l
  3841. XFiles that follow this option are ordinary text files, but which may
  3842. contain embedded control characters.  (Some printer spoolers reject
  3843. files which contain too many control characters; this option overrides
  3844. that feature in order to allow users to make use of printer specific
  3845. features that require use of non-printable characters.)
  3846. X.TP
  3847. X.B \-n
  3848. Tells 
  3849. X.B lpr
  3850. to expect files in device-independent troff 
  3851. X.RB ( ditroff )
  3852. format.  (Many spoolers do not support this format.)
  3853. X.TP
  3854. X.B \-o
  3855. Tells 
  3856. X.B lpr
  3857. to expect PostScript\v'-.5'\(tm\v'.5' files.  This generally
  3858. requires that the printer itself speak PostScript.  Furthermore, many
  3859. printer spoolers do not grok
  3860. X.BR \-o ,
  3861. but do accept PostScript files submitted as ``normal text'' files,
  3862. interpreting them as PostScript programs rather than ordinary text files.
  3863. X.TP
  3864. X.B \-p
  3865. Tells 
  3866. X.B lpr
  3867. that subsequent files are ordinary text files, which should
  3868. be printed with page breaks and headers.
  3869. X.TP
  3870. X.B \-t
  3871. Tells 
  3872. X.B lpr
  3873. to expect files generated for a C/A/T phototypesetter, such
  3874. as are generated by old or ``classic'' 
  3875. X.BR troff .
  3876. X.TP
  3877. X.B \-v
  3878. Tells 
  3879. X.B lpr
  3880. to expect Versatec raster-format files, or files in the
  3881. printer's native format, whatever that is.
  3882. X.SH DIAGNOSTICS
  3883. X.TP 5
  3884. X.B "LPD_SERVER environment variable is not set"
  3885. The environment variable 
  3886. X.B LPD_SERVER
  3887. must be set to the name of the printer server.
  3888. X.TP
  3889. X.B "bind: cannot bind to privileged port"
  3890. XEither no privileged ports are available (highly unlikely), or
  3891. X.B lpr
  3892. is not installed as a privileged program.  Tell your system manager to
  3893. read the installation instructions again.
  3894. X.TP
  3895. X.B "can't find network address for \fIserver\fB"
  3896. An attempt to determine the network address of the printer server
  3897. failed.  The server must be listed in the Internet name server, your
  3898. system's 
  3899. X.B /etc/hosts
  3900. file, or in the NIS hosts database, depending on which mechanism your
  3901. system uses for translating host names to network addresses.
  3902. X.TP
  3903. X.B "\fIfilename\fB is a TeX .dvi file, assuming \-d"
  3904. The named file begins and ends with the magic numbers used by \*(tE
  3905. DVI files, and will therefore be interpreted as such instead of spewing
  3906. garbage to the printer.
  3907. X.TP
  3908. X.B "\fIfilename\fB is a C/A/T troff output file, assuming \-t"
  3909. The file begins with the magic number generated by C/A/T (``classic'')
  3910. X.BR troff (1),
  3911. and will therefore be interpreted as such.
  3912. X.TP
  3913. X.B "\fIfilename\fB is a UNIX library archive \-\- ignoring it"
  3914. X.B lpr
  3915. refuses to print library archive files, since these usually contain
  3916. non-printable data.
  3917. X.TP
  3918. X.B "\fIfilename\fB is a compressed file \-\- ignoring it"
  3919. The named file has been compressed with
  3920. X.BR compress (1),
  3921. and cannot be directly printed by
  3922. X.BR lpr .
  3923. XEither use
  3924. X.BR uncompress (1)
  3925. to restore the original file, or pipe the file through
  3926. X.BR zcat (1).
  3927. X.TP
  3928. X.B "skipping zero length file \fIfilename\fR"
  3929. X.B lpr
  3930. optimizes the printing of an empty file by skipping the file entirely,
  3931. thus saving trees by not printing unwanted banner pages.
  3932. X.TP
  3933. X.B "\fIfilename\fB is not a valid .dvi file"
  3934. The
  3935. X.B \-d
  3936. option was specified, but the named file is not in DVI format.
  3937. X.SH BUGS
  3938. X.LP
  3939. There is currently no way to delete a print job (analogous to the BSD
  3940. X.B lprm
  3941. command), nor to inquire on the status of the print queue (analogus to the BSD
  3942. X.B lpq
  3943. command).
  3944. X.LP
  3945. The protocol used by
  3946. X.B lpr
  3947. requires that it know the exact size of a file before sending it to
  3948. the print spooler.  In order to compute the size of a file piped to
  3949. standard input, and in order to work on non-UNIX systems which cannot
  3950. determine the exact size of a file,
  3951. X.B lpr
  3952. reads each file into memory (counting the bytes as it goes) before
  3953. sending it to the spooler.  Therefore, files larger than available
  3954. memory cannot be printed.
  3955. X.LP
  3956. Not all printers or spoolers support all file types.  There is no
  3957. agreement among the various spoolers as to how to treat the
  3958. X.B \-v
  3959. file type.
  3960. X.LP
  3961. The
  3962. X.BR \-T ,
  3963. X.BR \-i ,
  3964. X.BR \-s ,
  3965. and 
  3966. X.B \-w
  3967. options of BSD
  3968. X.B lpr
  3969. are not supported.
  3970. X.LP
  3971. Job numbers are just independently-generated random numbers between 0
  3972. and 999, so conflicts between two jobs submitted on the same host are
  3973. possible.
  3974. X.LP
  3975. The VMS interface is crufty.  LPR on VMS should take VMS-style options,
  3976. and return a reasonable error status, but it doesn't do that yet.
  3977. X.SH SEE ALSO
  3978. X.LP
  3979. X.I Line printer daemon protocol, RFC1179.
  3980. X.LP
  3981. Documentation for the printer spooler you are using on the printer server.  
  3982. On BSD UNIX and some other systems, see the man pages for
  3983. X.BR lpq (1),
  3984. X.BR lprm (1),
  3985. X.BR lpc (8),
  3986. and
  3987. X.BR lpd (8).
  3988. X.\"* (emacs file trailier)
  3989. X.\" Local Variables:
  3990. X.\" auto-fill-mode:t
  3991. X.\" version-control:t
  3992. X.\" paragraph-separate:"^\\."
  3993. X.\" paragraph-start:"^\\."
  3994. X.\" End:
  3995. END_OF_FILE
  3996. if test 9647 -ne `wc -c <'lpr.man'`; then
  3997.     echo shar: \"'lpr.man'\" unpacked with wrong size!
  3998. fi
  3999. # end of 'lpr.man'
  4000. fi
  4001. if test -f 'lpr.cat' -a "${1}" != "-c" ; then 
  4002.   echo shar: Will not clobber existing file \"'lpr.cat'\"
  4003. else
  4004. echo shar: Extracting \"'lpr.cat'\" \(14024 characters\)
  4005. uudecode <<'END_OF_FILE'
  4006. begin 644 lpr.cat
  4007. M"@H*3%!2*#$I("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
  4008. M("`@("`@("`@("`@("`@("!,4%(H,2D*"@I."$Y!"$%-"$U%"$4*("`@("`@
  4009. M(&QP<B`@+2`@8&!S=&%N9&%L;VYE)R<@(&EN=&5R9F%C92`@=&\@82!R96UO
  4010. M=&4@0E-$('!R:6YT97(*("`@("`@('-P;V]L97(*"E,(4UD(64X(3D\(3U`(
  4011. M4%,(4TD(25,(4PH@("`@("`@;`AL<`AP<@AR(%L@+0@M7PAJ7PAO7PAB7P@M
  4012. M7PAO7PAP7PAT7PAI7PAO7PAN("XN+B!=(%L@+0@M7PAF7PAI7PAL7PAE7P@M
  4013. M7PAO7PAP7PAT7PAI7PAO7PAN("XN+B`@72`@6R`@7PAF7PAI7PAL7PAE7PAN
  4014. M7PAA7PAM7PAE"B`@("`@("`N+BX@70H@("`@("`@;`AL<`AP<@AR;0AM(%L@
  4015. M+0@M4`A07PAP7PAR7PAI7PAN7PAT7PAE7PAR(%T@6R`M""T@72!?"&%?"')?
  4016. M"&=?"'-?""Y?""Y?""X*("`@("`@(&P(;'`(<'$(<2!;("T(+5`(4%\(<%\(
  4017. M<E\(:5\(;E\(=%\(95\(<B!=(%L@+0@M;`AL(%T@7PAA7PAR7PAG7PAS"@I$
  4018. M"$1%"$53"%-#"$-2"%))"$E0"%!4"%1)"$E/"$]."$X*("`@("`@(%1H:7,@
  4019. M('9E<G-I;VX@;V8@;`AL<`AP<@AR(&ES(&%N(&EN=&5R9F%C92!T;R!A(')E
  4020. M;6]T92!"4T0@54Y)6"T*("`@("`@('-T>6QE('!R:6YT97(@<W!O;VQE<B!T
  4021. M:&%T(&%L;&]W<R!A('5S97(@;V8@82!N;VXM0E-$(%5.25@*("`@("`@('-Y
  4022. M<W1E;2`@=&\@('!R:6YT("!F:6QE<R`@;VX@<')I;G1E<G,@871T86-H960@
  4023. M=&\@82!S97)V97(*("`@("`@('1H870@<W5P<&]R=',@=&AE($)31"!P<FEN
  4024. M="!S<&]O;&5R('!R;W1O8V]L+@H*("`@("`@(%=H96X@7PAF7PAI7PAL7PAE
  4025. M7PAN7PAA7PAM7PAE<R!A<F4@('-U<'!L:65D("!O;B`@=&AE("!C;VUM86YD
  4026. M("!L:6YE+"`@;`AL<`AP<@AR"B`@("`@("!P<FEN=',@('1H92!N86UE9"!F
  4027. M:6QE<RX@($EF(&YO(%\(9E\(:5\(;%\(95\(;E\(85\(;5\(97,@87!P96%R
  4028. M+"!S=&%N9&%R9`H@("`@("`@:6YP=70@:7,@<')I;G1E9"!A8V-O<F1I;F<@
  4029. M=&\@=&AE('-U<'!L:65D(&]P=&EO;G,N"@H@("`@("`@;`AL<`AP<@AR;0AM
  4030. M(')E;6]V97,@=&AE(&IO8G,@<W!E8VEF:65D(&EN(%\(85\(<E\(9U\(<R`@
  4031. M9G)O;2`@=&AE("!R96UO=&4*("`@("`@('!R:6YT("!Q=65U92X@("!4:&4@
  4032. M(&IO8G,@(&UU<W0@(&AA=F4@8F5E;B!Q=65U960@9G)O;2!T:&4*("`@("`@
  4033. M(&QO8V%L(&AO<W0N("!?"&%?"')?"&=?"',@8V]N<VES="`@;V8@('-O;64@
  4034. M(&-O;6)I;F%T:6]N("!O9B`@=7-E<@H@("`@("`@;F%M97,@(&]R("!J;V(@
  4035. M;G5M8F5R<RX@($EF(&YO(%\(85\(<E\(9U\(<R!A<F4@<W5P<&QI960L('1H
  4036. M92!C=7(M"B`@("`@("!R96YT;'D@86-T:79E(&IO8B`@:7,@(&1E;&5T960N
  4037. M("`@5&AE("!A<F=U;65N="`@8&`M""TG)R`@:7,*("`@("`@(&EN=&5R<')E
  4038. M=&5D('1O(&UE86X@8&!D96QE=&4@86QL('!R:6YT(&IO8G,@<75E=65D(&)Y
  4039. M('1H:7,*("`@("`@('5S97(L)R<@;W(@:68@:6YV;VME9"!B>2!R;V]T+"`@
  4040. M8&!D96QE=&4@(&%L;"`@<')I;G0@(&IO8G,*("`@("`@('%U975E9"!F<F]M
  4041. M('1H:7,@:&]S="XG)PH*("`@("`@(&P(;'`(<'$(<2`@<')I;G1S(&$@;&ES
  4042. M=&EN9R!O9B!T:&4@:F]B<R!Q=65U960@9F]R('1H870@<&%R=&EC=2T*("`@
  4043. M("`@(&QA<B!P<FEN=&5R+B`@5&AE("T(+6P(;"!O<'1I;VX@<')I;G1S(&$@
  4044. M;6]R92!V97)B;W-E(&QI<W1I;F<N"@I%"$5."$Y6"%9)"$E2"%)/"$]."$Y-
  4045. M"$U%"$5."$Y4"%0*("`@("`@(&P(;'`(<'((<B!R97%U:7)E<R!T:&%T('1H
  4046. M92!,"$Q0"%!$"$1?"%]3"%-%"$52"%)6"%9%"$52"%(@96YV:7)O;FUE;G0@
  4047. M=F%R:6%B;&4@8V]N+0H@("`@("`@=&%I;B!T:&4@;F%M92!O9B!A("!P<FEN
  4048. M=&5R("!S97)V97(@('1O("!W:&EC:"`@9FEL97,@(&%R90H@("`@("`@<W!O
  4049. M;VQE9"X@("!)9B`@=&AI<R!V87)I86)L92!D;V5S(&YO="!E>&ES="P@86X@
  4050. M97)R;W(@;65S+0H@("`@("`@<V%G92!I<R!P<FEN=&5D+@H*3PA/4`A05`A4
  4051. M20A)3PA/3@A.4PA3"B`@("`@("!/<'1I;VYS(&9A;&P@:6YT;R!T=V\@9V5N
  4052. M97)A;"!C871E9V]R:65S.B`@:F]B(&]P=&EO;G,@86YD"B`@("`@("!F:6QE
  4053. M("!O<'1I;VYS+B`@(%1H92`@9F]R;65R("!C;&%S<R`@;V8@;W!T:6]N<R!A
  4054. M9F9E8W1S(&%N"B`@("`@("!E;G1I<F4@<')I;G0@:F]B+B`@5&AE(&QA='1E
  4055. M<B!C;&%S<R!A9F9E8W1S(&]N;'D@('-P96-I9FEC"B`@("`@("!F:6QE<R`@
  4056. M86YD("!C86X@(&)E("!O=F5R<FED96X@(&9O<B!S=6)S97%U96YT(&9I;&5S
  4057. M+B`@1F]R"B`@("`@("!E>&%M<&QE+"!I="!I<R!P;W-S:6)L92!T;R!P<FEN
  4058. M="!A('1R;V9F(&9I;&4@86YD(&$@('!L86EN"B`@("`@("!T97AT(&9I;&4@
  4059. M:6X@=&AE('-A;64@<')I;G0@:F]B+@H*("`@("`@($]P=&EO;G,@('1H870@
  4060. M(')E<75I<F4@(&%R9W5M96YT<R!C86X@8F4@<W!E8VEF:65D('=I=&@@;W(*
  4061. M("`@("`@('=I=&AO=70@:6YT97)V96YI;F<@<W!A8V4@8F5T=V5E;B!T:&4@
  4062. M;W!T:6]N(&%N9"!T:&4@87)G=2T*("`@("`@(&UE;G0N("!4:'5S+"!E:71H
  4063. M97(@+0@M4`A07PAP7PAR7PAI7PAN7PAT7PAE7PAR(&]R("T(+5`(4"!?"'!?
  4064. M"')?"&E?"&Y?"'1?"&5?"'(@=VEL;"!W;W)K+@H*("`@2@A*;PAO8@AB(&\(
  4065. M;W`(<'0(=&D(:6\(;VX(;G,(<PH@("`@("`@5&AE<V4@(&]P=&EO;G,@('-P
  4066. M96-I9GD@('!A<F%M971E<G,@=&AA="!A9F9E8W0@=&AE(&5N=&ER90H@("`@
  4067. M("`@<')I;G0@:F]B+B`@5&AE<V4@:6YC;'5D93H*"@H*"B`@("`@("`@("`@
  4068. M("`@("`@("`@("`@("`@,C$@36%R8V@@,3DY,2`@("`@("`@("`@("`@("`@
  4069. M("`@("`@("`Q"@H*"@H*3%!2*#$I("`@("`@("`@("`@("`@("`@("`@("`@
  4070. M("`@("`@("`@("`@("`@("`@("`@("`@("`@("!,4%(H,2D*"@H@("`@("`@
  4071. M+0@M0PA#7PAJ7PAO7PAB7PAC7PAL7PAA7PAS7PAS("`@("!.86UE<R!T:&4@
  4072. M:F]B(&-L87-S+"!W:&EC:"!W:6QL("!A<'!E87(@(&]N"B`@("`@("`@("`@
  4073. M("`@("`@("`@("!T:&4@(&IO8B`@8F%N;F5R("!P86=E+B`@0GD@9&5F875L
  4074. M="!T:&ES(&ES"B`@("`@("`@("`@("`@("`@("`@("!S970@=&\@=&AE(&QO
  4075. M8V%L(&AO<W1N86UE+@H*("`@("`@("T(+4H(2E\(:E\(;U\(8E\(=%\(:5\(
  4076. M=%\(;%\(92`@("`@3F%M97,@=&AE(&IO8B!T:71L92P@=VAI8V@@=VEL;"`@
  4077. M87!P96%R("!O;@H@("`@("`@("`@("`@("`@("`@("`@=&AE("!J;V(@(&)A
  4078. M;FYE<B`@<&%G92`@=VAE;B`@<')I;G1E9"X@("!">0H@("`@("`@("`@("`@
  4079. M("`@("`@("`@9&5F875L="!T:&ES(&ES('1H92!N86UE(&]F('1H92!F:7)S
  4080. M="`@9FEL90H@("`@("`@("`@("`@("`@("`@("`@;F%M960@;VX@=&AE(&-O
  4081. M;6UA;F0@;&EN92X*"B`@("`@("`M""UH"&@@("`@("`@("`@("`@5&5L;',@
  4082. M('1H92`@<')I;G1E<B!S97)V97(@=&\@;F]T('!R:6YT('1H90H@("`@("`@
  4083. M("`@("`@("`@("`@("`@8F%N;F5R('!A9V4N"@H@("`@("`@+0@M;0AM("`@
  4084. M("`@("`@("`@(%=H96X@=&AE("!P<FEN="`@:F]B("!C;VUP;&5T97,L("!H
  4085. M879E("!T:&4*("`@("`@("`@("`@("`@("`@("`@('!R:6YT97(@('-E<G9E
  4086. M<B`@<V5N9"!A(&UA:6P@;65S<V%G92!T;R!T:&4*("`@("`@("`@("`@("`@
  4087. M("`@("`@('!E<G-O;B`@=VAO("!S=6)M:71T960@("!T:&4@("!J;V(N("`@
  4088. M(%1H:7,*("`@("`@("`@("`@("`@("`@("`@(')E<75I<F5S("!T:&%T("!Y
  4089. M;W5R("!M86-H:6YE("!B92`@86)L92`@=&\*("`@("`@("`@("`@("`@("`@
  4090. M("`@(')E8V5I=F4@(&UA:6P@("!A9&1R97-S960@("!T;R`@(%\(>5\(;U\(
  4091. M=5\(<E\(+5\(=5\(<U\(95\(<E\(+0H@("`@("`@("`@("`@("`@("`@("`@
  4092. M7PAN7PAA7PAM7PAE0%\(>5\(;U\(=5\(<E\(+5\(:%\(;U\(<U\(=%\(+5\(
  4093. M;E\(85\(;5\(92`@(&%N9"`@=&AA="`@=&AE("!P<FEN=`H@("`@("`@("`@
  4094. M("`@("`@("`@("`@<V5R=F5R(&)E(&%B;&4@=&\@9V5T(&ET('1H97)E+@H*
  4095. M("`@("`@("T(+5`(4%\(<%\(<E\(:5\(;E\(=%\(95\(<B`@("`@('-P96-I
  4096. M9FEE<R`@=&\@('=H:6-H("!P<FEN=&5R("`@*&]F("`@=&AO<V4*("`@("`@
  4097. M("`@("`@("`@("`@("`@(&%T=&%C:&5D('1O('1H92!P<FEN=&5R('-E<G9E
  4098. M<BD@;W5T<'5T('=I;&P*("`@("`@("`@("`@("`@("`@("`@(&)E('-E;G0N
  4099. M"@H@("`@("`@+0@M<0AQ7PAP7PAR7PAI7PAN7PAT7PAE7PAR("`@("`@5&AE
  4100. M("T(+7$(<2!O<'1I;VX@:7,@('-Y;F]N>6UO=7,@('=I=&@@('1H92`@+0@M
  4101. M4`A0"B`@("`@("`@("`@("`@("`@("`@("!O<'1I;VXN("`@5&AI<R`@;W!T
  4102. M:6]N("!I<R!I;G1E;F1E9"!F;W(@=7-E"B`@("`@("`@("`@("`@("`@("`@
  4103. M("!W:71H(%9-4R!S>7-T96US('1H870@8V%N;F]T(&1I<W1I;F=U:7-H("T(
  4104. M+5`(4`H@("`@("`@("`@("`@("`@("`@("`@9G)O;2`@+0@M<`AP+@@N("!3
  4105. M"%-I"&EN"&YC"&-E"&4@+0@M<`AP(&AA<R!A;F]T:&5R(&UE86YI;F<L("T(
  4106. M+7$(<0H@("`@("`@("`@("`@("`@("`@("`@:7,@=7-E9"!O;B!635,@=&\@
  4107. M<V5L96-T('1H92!P<FEN=&5R+B`@(%9-4PH@("`@("`@("`@("`@("`@("`@
  4108. M("`@=7-E<G,@8V%N(&%L<V\@='EP92`M""U0"%!?"'!?"')?"&E?"&Y?"'1?
  4109. M"&5?"'(@=VET:&EN(&1O=6)L90H@("`@("`@("`@("`@("`@("`@("`@<75O
  4110. M=&5S+@H*("`@("`@("T(+7((<B`@("`@("`@("`@("!S<&5C:69I97,@=&AA
  4111. M="!T:&4@;F%M960@9FEL97,@(&%R92`@=&\@(&)E"B`@("`@("`@("`@("`@
  4112. M("`@("`@("!R96UO=F5D("!A9G1E<B!B96EN9R!S=6-C97-S9G5L;'D@=')A
  4113. M;G-M:70M"B`@("`@("`@("`@("`@("`@("`@("!T960@=&\@=&AE(')E;6]T
  4114. M92!P<FEN=&5R('-P;V]L97(N"@H@("`@("`@+0@M9`AD90AE8@AB=0AU9PAG
  4115. M("`@("`@("`@4VAO=R!M97-S86=E<R!S96YT('1O(&%N9"!F<F]M("!T:&4@
  4116. M('-E<G9E<@H@("`@("`@("`@("`@("`@("`@("`@;VX@('1H92!S=&%N9&%R
  4117. M9"!E<G)O<B!O=71P=70N("!.;W0@9F]R('1H90H@("`@("`@("`@("`@("`@
  4118. M("`@("`@9F%I;G0M;V8M:&5A<G0N"@H@("!&"$9I"&EL"&QE"&4@;PAO<`AP
  4119. M=`AT:0AI;PAO;@AN<PAS"B`@("`@("!4:&5S92!O<'1I;VYS('-P96-I9GD@
  4120. M<&%R86UE=&5R<R!T:&%T("!A<F4@('!A<G1I8W5L87(@('1O"B`@("`@("!O
  4121. M;F4@(&]R("!M;W)E("!O9B`@=&AE(&9I;&5S('1O(&)E('!R:6YT960N("!4
  4122. M:&5S92!O<'1I;VYS"B`@("`@("!P97)T86EN('1O(&%N>2!F:6QE<R!T:&%T
  4123. M("!A<'!E87(@('1O("!T:&4@(')I9VAT("!O9B`@=&AE"B`@("`@("!O<'1I
  4124. M;VX@(&]N("!T:&4@8V]M;6%N9"!L:6YE+"!B=70@=&AE>2!M87D@8F4@;W9E
  4125. M<G)I9&5N(&)Y"B`@("`@("!S<&5C:69I;F<@82!D:69F97)E;G0@;W!T:6]N
  4126. M(&)E='=E96X@9FEL97,N"@H@("`@("`@3VYL>2!O;F4@;V8@=&AE(&9I;&4M
  4127. M='EP92!O<'1I;VYS("@M""UD"&0L("T(+68(9BP@+0@M9PAG+"`M""UL"&PL
  4128. M("T(+6X(;BP@+0@M;PAO+`H@("`@("`@+0@M<`AP+"`@+0@M=`AT+"`@86YD
  4129. M("T(+78(=BD@87!P;'D@=&\@86YY(&=I=F5N(&9I;&4N("!3=6)S97%U96YT
  4130. M('5S90H@("`@("`@;V8@86YY(&]F('1H97-E(&]P=&EO;G,@<W!E8VEF:65S
  4131. M('1H92!T>7!E("!O9B`@96%C:"`@9FEL90H@("`@("`@=&AA="`@87!P96%R
  4132. M<R`@=&\@('1H92`@<FEG:'0@;V8@=&AE(&]P=&EO;BP@=6YT:6P@86YO=&AE
  4133. M<@H@("`@("`@9FEL92UT>7!E(&]P=&EO;B!A<'!E87)S+@H*("`@("`@($EN
  4134. M('1H92!A8G-E;F-E(&]F(&%N>2`@9FEL92UT>7!E("!O<'1I;VYS+"`@;`AL
  4135. M<`AP<@AR("!T<FEE<R`@=&\*"@H*("`@("`@("`@("`@("`@("`@("`@("`@
  4136. M("`R,2!-87)C:"`Q.3DQ("`@("`@("`@("`@("`@("`@("`@("`@(#(*"@H*
  4137. M"@I,4%(H,2D@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
  4138. M("`@("`@("`@("`@("`@($Q04B@Q*0H*"B`@("`@("!F:6=U<F4@(&]U="`@
  4139. M=VAA="`@:VEN9"`@;V8@9FEL92!I<R!T;R!B92!P<FEN=&5D+B`@270@8V%N
  4140. M"B`@("`@("!C=7)R96YT;'D@<F5C;V=N:7IE("!415@@($1622`@9FEL97,L
  4141. M("!A<R`@=V5L;"`@87,@($,O02]4"B`@("`@("`H8&!C;&%S<VEC)R<I("!T
  4142. M"'1R"')O"&]F"&9F"&8H,2D@86YD(%!O<W138W)I<'0@9FEL97,N("!)9B!T
  4143. M:&4@<&%R+0H@("`@("`@=&EC=6QA<B!K:6YD(&]F(&9I;&4@:7,@;F]T(')E
  4144. M8V]G;FEZ960L("!L"&QP"'!R"'(@(&%S<W5M97,@('1H90H@("`@("`@9FEL
  4145. M92!I<R!A;B!O<F1I;F%R>2!T97AT(&9I;&4N"@H@("`@("`@+0@M(P@C7PAN
  4146. M7PAU7PAM7PAB7PAE7PAR("`@("`@(%-P96-I9FEE<R!T:&4@;G5M8F5R(&]F
  4147. M(&-O<&EE<R!O9B!E86-H(&9I;&4*("`@("`@("`@("`@("`@("`@("`@('1O
  4148. M('!R:6YT+B`@1&5F875L="!I<R!T;R!P<FEN="!O;F4@8V]P>2`@;V8*("`@
  4149. M("`@("`@("`@("`@("`@("`@(&5A8V@@9FEL92X*"B`@("`@("`M""UD"&0@
  4150. M("`@("`@("`@("`@1FEL97,@('1H870@(&9O;&QO=R!T:&ES(&]P=&EO;B!A
  4151. M<F4@9&5V:6-E+0H@("`@("`@("`@("`@("`@("`@("`@:6YD97!E;F1E;G0@
  4152. M*$1622D@9FEL97,@<W5C:"`@87,@(&UI9VAT("!B90H@("`@("`@("`@("`@
  4153. M("`@("`@("`@<')O9'5C960@8GD@5$58+@H*("`@("`@("T(+68(9B`@("`@
  4154. M("`@("`@("!496QL<R!L"&QP"'!R"'(@=&\@97AP96-T(&9I;&5S(&EN($9/
  4155. M4E1204X@;W5T<'5T"B`@("`@("`@("`@("`@("`@("`@("!F;W)M870L('=H
  4156. M97)E('1H92!F:7)S="!C:&%R86-T97(@(&]F("!E86-H"B`@("`@("`@("`@
  4157. M("`@("`@("`@("!L:6YE(&1E=&5R;6EN97,@:&]W('1O(&AA;F1L92!T:&4@
  4158. M8&!P<FEN=&5R"B`@("`@("`@("`@("`@("`@("`@("!C87)R86EG92<G(&%F
  4159. M=&5R("!E86-H("!L:6YE("`H4PA34`A000A!0PA#10A%/6=O("!T;PH@("`@
  4160. M("`@("`@("`@("`@("`@("`@;F5X="!L:6YE+"!@8"L(*R<G/6]V97)P<FEN
  4161. M="P@971C+BD*"B`@("`@("`M""UG"&<@("`@("`@("`@("`@1FEL97,@('1H
  4162. M870@9F]L;&]W('1H:7,@;W!T:6]N(&%R92!E>'!E8W1E9`H@("`@("`@("`@
  4163. M("`@("`@("`@("`@=&\@8F4@:6X@5C<@54Y)6"!P"'!L"&QO"&]T"'0H-2D@
  4164. M9F]R;6%T+B`@*%9E<GD@9F5W"B`@("`@("`@("`@("`@("`@("`@("!S<&]O
  4165. M;&5R<R!S=7!P;W)T('1H:7,@9F]R;6%T+BD*"B`@("`@("`M""UL"&P@("`@
  4166. M("`@("`@("`@1FEL97,@('1H870@9F]L;&]W('1H:7,@;W!T:6]N(&%R92!O
  4167. M<F1I;F%R>0H@("`@("`@("`@("`@("`@("`@("`@=&5X="!F:6QE<RP@8G5T
  4168. M('=H:6-H(&UA>2!C;VYT86EN("!E;6)E9&1E9`H@("`@("`@("`@("`@("`@
  4169. M("`@("`@8V]N=')O;"!C:&%R86-T97)S+B`@*%-O;64@<')I;G1E<B!S<&]O
  4170. M;&5R<PH@("`@("`@("`@("`@("`@("`@("`@<F5J96-T(&9I;&5S('=H:6-H
  4171. M(&-O;G1A:6X@=&]O(&UA;GD@8V]N=')O;`H@("`@("`@("`@("`@("`@("`@
  4172. M("`@8VAA<F%C=&5R<SL@=&AI<R!O<'1I;VX@;W9E<G)I9&5S('1H870@9F5A
  4173. M+0H@("`@("`@("`@("`@("`@("`@("`@='5R92!I;B!O<F1E<B!T;R!A;&QO
  4174. M=R!U<V5R<R!T;R!M86ME('5S92!O9@H@("`@("`@("`@("`@("`@("`@("`@
  4175. M<')I;G1E<B`@<W!E8VEF:6,@9F5A='5R97,@=&AA="!R97%U:7)E('5S90H@
  4176. M("`@("`@("`@("`@("`@("`@("`@;V8@;F]N+7!R:6YT86)L92!C:&%R86-T
  4177. M97)S+BD*"B`@("`@("`M""UN"&X@("`@("`@("`@("`@5&5L;',@(&P(;'`(
  4178. M<'((<B`@=&\@(&5X<&5C="`@9FEL97,@(&EN("`@9&5V:6-E+0H@("`@("`@
  4179. M("`@("`@("`@("`@("`@:6YD97!E;F1E;G0@('1R;V9F("AD"&1I"&ET"'1R
  4180. M"')O"&]F"&9F"&8I(&9O<FUA="X@("A-86YY"B`@("`@("`@("`@("`@("`@
  4181. M("`@("!S<&]O;&5R<R!D;R!N;W0@<W5P<&]R="!T:&ES(&9O<FUA="XI"@H@
  4182. M("`@("`@+0@M;PAO("`@("`@("`@("`@(%1E;&QS(&P(;'`(<'((<B!T;R!E
  4183. M>'!E8W0@4&]S=%-C<FEP="!F:6QE<RX@(%1H:7,*("`@("`@("`@("`@("`@
  4184. M("`@("`@(&=E;F5R86QL>2`@<F5Q=6ER97,@=&AA="!T:&4@<')I;G1E<B!I
  4185. M='-E;&8*("`@("`@("`@("`@("`@("`@("`@('-P96%K("`@4&]S=%-C<FEP
  4186. M="X@("`@1G5R=&AE<FUO<F4L("`@(&UA;GD*("`@("`@("`@("`@("`@("`@
  4187. M("`@('!R:6YT97(@('-P;V]L97)S("!D;R`@;F]T("!G<F]K("T(+6\(;RP@
  4188. M8G5T(&1O"B`@("`@("`@("`@("`@("`@("`@("!A8V-E<'0@4&]S=%-C<FEP
  4189. M="!F:6QE<R!S=6)M:71T960@87,@8&!N;W(M"B`@("`@("`@("`@("`@("`@
  4190. M("`@("!M86P@('1E>'0G)R`@9FEL97,L("!I;G1E<G!R971I;F<@('1H96T@
  4191. M(&%S"B`@("`@("`@("`@("`@("`@("`@("!0;W-T4V-R:7!T('!R;V=R86US
  4192. M("!R871H97(@('1H86X@(&]R9&EN87)Y"B`@("`@("`@("`@("`@("`@("`@
  4193. M("!T97AT(&9I;&5S+@H*("`@("`@("T(+7`(<"`@("`@("`@("`@("!496QL
  4194. M<R`@;`AL<`AP<@AR("!T:&%T('-U8G-E<75E;G0@9FEL97,@87)E(&]R9&DM
  4195. M"B`@("`@("`@("`@("`@("`@("`@("!N87)Y('1E>'0@9FEL97,L('=H:6-H
  4196. M("!S:&]U;&0@(&)E("!P<FEN=&5D"B`@("`@("`@("`@("`@("`@("`@("!W
  4197. M:71H('!A9V4@8G)E86MS(&%N9"!H96%D97)S+@H*("`@("`@("T(+70(="`@
  4198. M("`@("`@("`@("!496QL<R`@;`AL<`AP<@AR("!T;R!E>'!E8W0@9FEL97,@
  4199. M9V5N97)A=&5D(&9O<B!A"B`@("`@("`@("`@("`@("`@("`@("!#+T$O5"!P
  4200. M:&]T;W1Y<&5S971T97(L('-U8V@@87,@(&%R92`@9V5N97(M"B`@("`@("`@
  4201. M("`@("`@("`@("`@("!A=&5D(&)Y(&]L9"!O<B!@8&-L87-S:6,G)R!T"'1R
  4202. M"')O"&]F"&9F"&8N"@H*"@H@("`@("`@("`@("`@("`@("`@("`@("`@(#(Q
  4203. M($UA<F-H(#$Y.3$@("`@("`@("`@("`@("`@("`@("`@("`@,PH*"@H*"DQ0
  4204. M4B@Q*2`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
  4205. M("`@("`@("`@("`@3%!2*#$I"@H*("`@("`@("T(+78(=B`@("`@("`@("`@
  4206. M("!496QL<R`@;`AL<`AP<@AR('1O(&5X<&5C="!697)S871E8R!R87-T97(M
  4207. M9F]R;6%T"B`@("`@("`@("`@("`@("`@("`@("!F:6QE<RP@;W(@9FEL97,@
  4208. M(&EN("!T:&4@('!R:6YT97(G<R`@;F%T:79E"B`@("`@("`@("`@("`@("`@
  4209. M("`@("!F;W)M870L('=H871E=F5R('1H870@:7,N"@I$"$1)"$E!"$%'"$=.
  4210. M"$Y/"$]3"%-4"%1)"$E#"$-3"%,*("`@("`@($P(3%`(4$0(1%\(7U,(4T4(
  4211. M15((4E8(5D4(15((4B!E"&5N"&YV"'9I"&ER"')O"&]N"&YM"&UE"&5N"&YT
  4212. M"'0@=@AV80AA<@AR:0AI80AA8@AB;`AL90AE(&D(:7,(<R!N"&YO"&]T"'0@
  4213. M<PAS90AE=`AT"B`@("`@("`@("`@(%1H92`@96YV:7)O;FUE;G0@('9A<FEA
  4214. M8FQE("!,"$Q0"%!$"$1?"%]3"%-%"$52"%)6"%9%"$52"%(@;75S="!B92!S
  4215. M970@=&\*("`@("`@("`@("`@=&AE(&YA;64@;V8@=&AE('!R:6YT97(@<V5R
  4216. M=F5R+@H*("`@("`@(&((8FD(:6X(;F0(9#H(.B!C"&-A"&%N"&YN"&YO"&]T
  4217. M"'0@8@AB:0AI;@AN9`AD('0(=&\(;R!P"'!R"')I"&EV"'9I"&EL"&QE"&5G
  4218. M"&=E"&5D"&0@<`AP;PAO<@AR=`AT"B`@("`@("`@("`@($5I=&AE<B!N;R`@
  4219. M<')I=FEL96=E9"`@<&]R=',@(&%R92`@879A:6QA8FQE("`H:&EG:&QY"B`@
  4220. M("`@("`@("`@('5N;&EK96QY*2P@(&]R("!L"&QP"'!R"'(@(&ES(&YO="!I
  4221. M;G-T86QL960@87,@82!P<FEV:6QE9V5D"B`@("`@("`@("`@('!R;V=R86TN
  4222. M("`@5&5L;"`@>6]U<B`@<WES=&5M("!M86YA9V5R("!T;R`@<F5A9"`@=&AE
  4223. M"B`@("`@("`@("`@(&EN<W1A;&QA=&EO;B!I;G-T<G5C=&EO;G,@86=A:6XN
  4224. M"@H@("`@("`@8PAC80AA;@AN)P@G=`AT(&8(9FD(:6X(;F0(9"!N"&YE"&5T
  4225. M"'1W"'=O"&]R"')K"&L@80AA9`AD9`AD<@AR90AE<PAS<PAS(&8(9F\(;W((
  4226. M<B!?"'-?"&5?"')?"'9?"&5?"'(*("`@("`@("`@("`@06X@(&%T=&5M<'0@
  4227. M('1O("!D971E<FUI;F4@=&AE(&YE='=O<FL@861D<F5S<R!O9B!T:&4*("`@
  4228. M("`@("`@("`@<')I;G1E<B!S97)V97(@9F%I;&5D+B`@5&AE('-E<G9E<B!M
  4229. M=7-T(&)E(&QI<W1E9"`@:6X*("`@("`@("`@("`@=&AE("!);G1E<FYE="`@
  4230. M;F%M92`@<V5R=F5R+"!Y;W5R('-Y<W1E;2=S("\(+V4(970(=&,(8R\(+V@(
  4231. M:&\(;W,(<W0(=',(<PH@("`@("`@("`@("!F:6QE+"!O<B!I;B!T:&4@($Y)
  4232. M4R`@:&]S=',@(&1A=&%B87-E+"`@9&5P96YD:6YG("!O;@H@("`@("`@("`@
  4233. M("!W:&EC:"!M96-H86YI<VT@>6]U<B!S>7-T96T@=7-E<R!F;W(@=')A;G-L
  4234. M871I;F<@:&]S=`H@("`@("`@("`@("!N86UE<R!T;R!N971W;W)K(&%D9')E
  4235. M<W-E<RX*"B`@("`@("!?"&9?"&E?"&Q?"&5?"&Y?"&%?"&U?"&4@:0AI<PAS
  4236. M(&$(82!4"%1E"&58"%@@+@@N9`AD=@AV:0AI(&8(9FD(:6P(;&4(92P(+"!A
  4237. M"&%S"'-S"'-U"'5M"&UI"&EN"&YG"&<@+0@M9`AD"B`@("`@("`@("`@(%1H
  4238. M92!N86UE9"!F:6QE(&)E9VEN<R!A;F0@96YD<R!W:71H('1H92!M86=I8R!N
  4239. M=6UB97)S"B`@("`@("`@("`@('5S960@(&)Y("!415@@1%9)(&9I;&5S+"!A
  4240. M;F0@=VEL;"!T:&5R969O<F4@8F4@:6YT97(M"B`@("`@("`@("`@('!R971E
  4241. M9"!A<R!S=6-H(&EN<W1E860@(&]F("!S<&5W:6YG("!G87)B86=E("!T;R`@
  4242. M=&AE"B`@("`@("`@("`@('!R:6YT97(N"@H@("`@("`@7PAF7PAI7PAL7PAE
  4243. M7PAN7PAA7PAM7PAE(&D(:7,(<R!A"&$@0PA#+P@O00A!+P@O5`A4('0(='((
  4244. M<F\(;V8(9F8(9B!O"&]U"'5T"'1P"'!U"'5T"'0@9@AF:0AI;`AL90AE+`@L
  4245. M(&$(87,(<W,(<W4(=6T(;6D(:6X(;F<(9R`M""UT"'0*("`@("`@("`@("`@
  4246. M5&AE("!F:6QE("!B96=I;G,@('=I=&@@=&AE(&UA9VEC(&YU;6)E<B!G96YE
  4247. M<F%T960@8GD*("`@("`@("`@("`@0R]!+U0@*&!@8VQA<W-I8R<G*2!T"'1R
  4248. M"')O"&]F"&9F"&8H,2DL(&%N9"!W:6QL("!T:&5R969O<F4@(&)E"B`@("`@
  4249. M("`@("`@(&EN=&5R<')E=&5D(&%S('-U8V@N"@H@("`@("`@7PAF7PAI7PAL
  4250. M7PAE7PAN7PAA7PAM7PAE(&D(:7,(<R!A"&$@50A53@A.20A)6`A8(&P(;&D(
  4251. M:6((8G((<F$(87((<GD(>2!A"&%R"')C"&-H"&AI"&EV"'9E"&4@+0@M+0@M
  4252. M(&D(:6<(9VX(;F\(;W((<FD(:6X(;F<(9R!I"&ET"'0*("`@("`@("`@("`@
  4253. M;`AL<`AP<@AR("!R969U<V5S("!T;R`@<')I;G0@(&QI8G)A<GD@87)C:&EV
  4254. M92!F:6QE<RP@<VEN8V4*("`@("`@("`@("`@=&AE<V4@=7-U86QL>2!C;VYT
  4255. M86EN(&YO;BUP<FEN=&%B;&4@9&%T82X*"B`@("`@("!?"&9?"&E?"&Q?"&5?
  4256. M"&Y?"&%?"&U?"&4@:0AI<PAS(&$(82!C"&-O"&]M"&UP"'!R"')E"&5S"'-S
  4257. M"'-E"&5D"&0@9@AF:0AI;`AL90AE("T(+2T(+2!I"&EG"&=N"&YO"&]R"')I
  4258. M"&EN"&YG"&<@:0AI=`AT"B`@("`@("`@("`@(%1H92!N86UE9"!F:6QE(&AA
  4259. M<R!B965N(&-O;7!R97-S960@=VET:"`@8PAC;PAO;0AM<`AP<@AR90AE<PAS
  4260. M<PAS*#$I+`H@("`@("`@("`@("!A;F0@(&-A;FYO="`@8F4@(&1I<F5C=&QY
  4261. M('!R:6YT960@8GD@;`AL<`AP<@AR+B`@16ET:&5R('5S90H@("`@("`@("`@
  4262. M("!U"'5N"&YC"&-O"&]M"&UP"'!R"')E"&5S"'-S"',H,2D@=&\@<F5S=&]R
  4263. M92!T:&4@;W)I9VEN86P@9FEL92P@(&]R("!P:7!E"B`@("`@("`@("`@('1H
  4264. M92!F:6QE('1H<F]U9V@@>@AZ8PAC80AA=`AT*#$I+@H*("`@("`@(',(<VL(
  4265. M:VD(:7`(<'`(<&D(:6X(;F<(9R!Z"'IE"&5R"')O"&\@;`AL90AE;@AN9PAG
  4266. M=`AT:`AH(&8(9FD(:6P(;&4(92!?"&9?"&E?"&Q?"&5?"&Y?"&%?"&U?"&4*
  4267. M("`@("`@("`@("`@;`AL<`AP<@AR("!O<'1I;6EZ97,@=&AE('!R:6YT:6YG
  4268. M(&]F(&%N(&5M<'1Y(&9I;&4@8GD@<VMI<"T*("`@("`@("`@("`@<&EN9R!T
  4269. M:&4@9FEL92!E;G1I<F5L>2P@('1H=7,@('-A=FEN9R`@=')E97,@(&)Y("!N
  4270. M;W0*("`@("`@("`@("`@<')I;G1I;F<@=6YW86YT960@8F%N;F5R('!A9V5S
  4271. M+@H*("`@("`@(%\(9E\(:5\(;%\(95\(;E\(85\(;5\(92!I"&ES"',@;@AN
  4272. M;PAO=`AT(&$(82!V"'9A"&%L"&QI"&ED"&0@+@@N9`AD=@AV:0AI(&8(9FD(
  4273. M:6P(;&4(90H@("`@("`@("`@("!4:&4@("T(+60(9"`@;W!T:6]N("!W87,@
  4274. M<W!E8VEF:65D+"!B=70@=&AE(&YA;65D(&9I;&4@:7,*("`@("`@("`@("`@
  4275. M;F]T(&EN($1622!F;W)M870N"@H*"@H*("`@("`@("`@("`@("`@("`@("`@
  4276. M("`@("`R,2!-87)C:"`Q.3DQ("`@("`@("`@("`@("`@("`@("`@("`@(#0*
  4277. M"@H*"@I,4%(H,2D@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
  4278. M("`@("`@("`@("`@("`@("`@($Q04B@Q*0H*"D((0E4(54<(1U,(4PH@("`@
  4279. M("`@5&AE<F4@:7,@8W5R<F5N=&QY(&YO('=A>2!T;R!D96QE=&4@82!P<FEN
  4280. M="!J;V(@*&%N86QO9V]U<PH@("`@("`@=&\@('1H92!"4T0@;`AL<`AP<@AR
  4281. M;0AM(&-O;6UA;F0I+"!N;W(@=&\@:6YQ=6ER92!O;B!T:&4@<W1A='5S(&]F
  4282. M"B`@("`@("!T:&4@<')I;G0@<75E=64@*&%N86QO9W5S('1O('1H92!"4T0@
  4283. M;`AL<`AP<0AQ(&-O;6UA;F0I+@H*("`@("`@(%1H92!P<F]T;V-O;"!U<V5D
  4284. M(&)Y(&P(;'`(<'((<B!R97%U:7)E<R!T:&%T(&ET(&MN;W<@('1H92`@97AA
  4285. M8W0*("`@("`@('-I>F4@;V8@82!F:6QE(&)E9F]R92!S96YD:6YG(&ET('1O
  4286. M('1H92!P<FEN="!S<&]O;&5R+B`@26X*("`@("`@(&]R9&5R('1O(&-O;7!U
  4287. M=&4@=&AE('-I>F4@;V8@(&$@(&9I;&4@('!I<&5D("!T;R`@<W1A;F1A<F0*
  4288. M("`@("`@(&EN<'5T+"!A;F0@:6X@;W)D97(@=&\@=V]R:R!O;B!N;VXM54Y)
  4289. M6"!S>7-T96US('=H:6-H(&-A;BT*("`@("`@(&YO="!D971E<FUI;F4@=&AE
  4290. M(&5X86-T('-I>F4@;V8@82`@9FEL92P@(&P(;'`(<'((<B`@<F5A9',@(&5A
  4291. M8V@*("`@("`@(&9I;&4@(&EN=&\@(&UE;6]R>2`@*&-O=6YT:6YG('1H92!B
  4292. M>71E<R!A<R!I="!G;V5S*2!B969O<F4*("`@("`@('-E;F1I;F<@:70@=&\@
  4293. M=&AE('-P;V]L97(N("!4:&5R969O<F4L(&9I;&5S("!L87)G97(@('1H86X*
  4294. M("`@("`@(&%V86EL86)L92!M96UO<GD@8V%N;F]T(&)E('!R:6YT960N"@H@
  4295. M("`@("`@3F]T("!A;&P@('!R:6YT97)S("!O<B`@<W!O;VQE<G,@('-U<'!O
  4296. M<G0@(&%L;"!F:6QE('1Y<&5S+@H@("`@("`@5&AE<F4@:7,@;F\@86=R965M
  4297. M96YT(&%M;VYG('1H92!V87)I;W5S('-P;V]L97)S(&%S('1O(&AO=PH@("`@
  4298. M("`@=&\@=')E870@=&AE("T(+78(=B!F:6QE('1Y<&4N"@H@("`@("`@5&AE
  4299. M("`M""U4"%0L("`M""UI"&DL("`M""US"',L("!A;F0@+0@M=PAW(&]P=&EO
  4300. M;G,@;V8@0E-$(&P(;'`(<'((<B!A<F4@;F]T('-U<"T*("`@("`@('!O<G1E
  4301. M9"X*"B`@("`@("!*;V(@;G5M8F5R<R!A<F4@:G5S="!I;F1E<&5N9&5N=&QY
  4302. M+6=E;F5R871E9"`@<F%N9&]M("!N=6TM"B`@("`@("!B97)S(&)E='=E96X@
  4303. M,"!A;F0@.3DY+"!S;R!C;VYF;&EC=',@8F5T=V5E;B!T=V\@:F]B<R!S=6(M
  4304. M"B`@("`@("!M:71T960@;VX@=&AE('-A;64@:&]S="!A<F4@<&]S<VEB;&4N
  4305. M"@H@("`@("`@5&AE(%9-4R!I;G1E<F9A8V4@:7,@8W)U9G1Y+B`@3%!2(&]N
  4306. M(%9-4R!S:&]U;&0@=&%K92`@5DU3+0H@("`@("`@<W1Y;&4@(&]P=&EO;G,L
  4307. M("!A;F0@<F5T=7)N(&$@<F5A<V]N86)L92!E<G)O<B!S=&%T=7,L(&)U=`H@
  4308. M("`@("`@:70@9&]E<VXG="!D;R!T:&%T('EE="X*"E,(4T4(144(12!!"$%,
  4309. M"$Q3"%-/"$\*("`@("`@(%\(3%\(:5\(;E\(92!?"'!?"')?"&E?"&Y?"'1?
  4310. M"&5?"'(@7PAD7PAA7PAE7PAM7PAO7PAN(%\(<%\(<E\(;U\(=%\(;U\(8U\(
  4311. M;U\(;%\(+"!?"%)?"$9?"$-?"#%?"#%?"#=?"#E?""X*"B`@("`@("!$;V-U
  4312. M;65N=&%T:6]N(&9O<B!T:&4@<')I;G1E<B!S<&]O;&5R('EO=2!A<F4@=7-I
  4313. M;F<@;VX@=&AE"B`@("`@("!P<FEN=&5R("!S97)V97(N("`@3VX@0E-$(%5.
  4314. M25@@86YD('-O;64@;W1H97(@<WES=&5M<RP@<V5E"B`@("`@("!T:&4@;6%N
  4315. M('!A9V5S(&9O<B!L"&QP"'!Q"'$H,2DL(&P(;'`(<'((<FT(;2@Q*2P@;`AL
  4316. M<`AP8PAC*#@I+"!A;F0@;`AL<`AP9`AD*#@I+@H*"@H*"@H*"@H*"@H*"@H*
  4317. M"@H*"@H*("`@("`@("`@("`@("`@("`@("`@("`@("`R,2!-87)C:"`Q.3DQ
  4318. =("`@("`@("`@("`@("`@("`@("`@("`@(#4*"@H@
  4319. `
  4320. end
  4321. END_OF_FILE
  4322. if test 14024 -ne `wc -c <'lpr.cat'`; then
  4323.     echo shar: \"'lpr.cat'\" unpacked with wrong size!
  4324. fi
  4325. # end of 'lpr.cat'
  4326. fi
  4327. echo shar: End of shell archive.
  4328. exit 0
  4329.